软件频道>程序开发>JavaVBVCDelphiC/C++Web开发微软专栏移动数据库程序人生软件工程|开发客
您现在的位置: 天极网 > 开发频道 > DB2 的 pureXML 特性与 Ruby on Rails
全文

DB2 的 pureXML 特性与 Ruby on Rails

2007-12-13 10:36作者:John Chun出处:论坛整理责任编辑:方舟
  可以将一份文本文档格式的市场营销报告与上面的 XML 客户数据关联起来。市场营销报告可以包含市场分析结果或者关于数据收集方式的细节。

  在第 1 部分中,我们创建了一个 XML 类型的列来存储收集的市场营销数据。为了高效地管理 XML 数据,像传统的 SQL 数据类型一样,DB2 在内部使用 XML 数据模型作为逻辑数据模型,同时 也作为物理存储的基本单元。另外,当指定 XML 数据类型时,会向数据库用户公开这个数据模型。尽管这为管理 XML 数据提供了强大的功能和灵活性,尤其适合以 XML 为中心的开发人员,但是当前对于能够在 XML 列上执行的传统数据库管理活动类型还有一些限制。例如,包含 XML 列的表无法由 DB2 进行物理重组,这是因为 XML 具有层次化的存储结构。这实际上意味着,在包含 XML 列的表中,不能用 ALTER 操作删除列。尽管未来的 DB2 版本中可能会取消这个限制,但是现在要记住这个限制,因为这是 Ruby on Rails 迁移的一个基本操作。

  为了继续利用 Ruby on Rails 迁移的灵活性,同时保持 XML 的强大功能,我们要创建一个单独的表来存储 XML 数据。我们将这个表命名为 XML_CONTENTS。它将存储 XML 文档,DOCUMENTS 表仍然存储其他所有相关信息。以后可以在 DOCUMENTS 表中添加或删除列,而不会受到 XML_CONTENTS 表中 XML 数据的影响,也不会影响这些 XML 数据。

  关于当前使用 XML 数据类型的限制的更多细节,请参考 IBM DB2 Database for Linux, UNIX, and Windows Information Center 中的 “Restrictions on native XML data store” 部分。

  为了执行这个任务,我们生成并运行以下迁移:

  a) 运行 ruby script/generate migration create_xml_contents,这将创建 db/migrate/010_create_xml_contents.rb 文件。

  b) 编辑 db/migrate/010_create_xml_contents.rb 文件:

  清单 4. 编辑 010_create_xml_contents.rb

 class CreateXmlContents < ActiveRecord::Migration
  def self.up
    drop_table :documents
    create_table :documents do |t|
      t.column :name,         :string,   :null => false
      t.column :size,         :integer,  :null => false
      t.column :data,         :binary,   :limit => 2.megabytes
      t.column :content_type, :string,   :null => false
      t.column :created_at,   :timestamp
      t.column :updated_at,   :timestamp
      t.column :platform,     :string,   :limit =>10
      t.column :subject_id,   :integer
      t.column :user_id,      :integer
    end
    create_table :xml_contents do |t|
      t.column :name,        :string
      t.column :data,        :xml,       :null => false
      t.column :document_id, :integer
    end
  end

  def self.down
    drop_table :documents
    drop_table :xml_contents
    create_table :documents do |t|
      t.column :name,           :string,   :null => false
      t.column :size,           :integer,  :null => false
      t.column :data,           :binary,   :limit => 2.megabytes
      t.column :content_type,   :string,   :null => false
      t.column :created_at,     :timestamp
      t.column :updated_at,     :timestamp
      t.column :platform,       :string,   :limit =>10
      t.column :subject_id,     :integer
      t.column :user_id,        :integer
      t.column :xmldata,        :xml,      :null => false
    end
  end
end

  c) 运行 rake db:migrate 以删除现有的 DOCUMENTS 表、创建只存储 XML 数据的新表 XML_CONTENTS 和新的 DOCUMENTS 表(不包含 XML 列)。

  d) 在新的 DOCUMENTS 表和 XML_CONTENTS 表之间重新建立一个关系。

  首先,在步骤 d 中生成的 /app/models/xml_content.rb 中添加 belongs_to :document 关联。

  第二,在 /app/models/document.rb 文件中添加 has_one :xml_content 关联。

  e) 上载功能与以前的文档模型(document.rb,现在变成了父模型)中的实现相似,并添加创建子模型(xml_content)的操作。

  NAME 列中存储原来的文件名。

  清单 5. 在 DOCUMENTS 记录中指定文件属性

self.name = File.basename(doc_field.original_filename).gsub(/[^\w._-]/, '')
self.content_type  = doc_field.content_type.chomp
self.size = doc_field.size
self.created_at = Time.now

  XML_CONTENTS.DATA 列存储指定的文件。

  清单 6. 向 XML_CONTENTS.DATA 指定 XML 文件内容

 unless self.content_type.include?('text/xml')
  self.data = doc_field.read
else
  content = XmlContent.new
  content.name = self.name
  content.data = doc_field.read
  self.xml_content = content
end

  最终的 /app/models/document.rb 应该像清单 7 这样。

  清单 7. document.rb

class Document < ActiveRecord::Base
  belongs_to  :user
  belongs_to  :subject
  has_one     :xml_content

  #           values  displayed  |  stored
  PLATFORM_TYPES = [ ['Neutral',    'Any'],
                     ['Windows',    'WinXP'],
                     ['Mac OS X',   'MacOS'],
                     ['Linux',      'Linux']]


  def uploaded_doc=(doc_field)
    self.name = File.basename(doc_field.original_filename).gsub(/[^\w._-]/, '')
    self.content_type  = doc_field.content_type.chomp
    self.size = doc_field.size
    self.created_at = Time.now
    unless self.content_type.include?('text/xml')
      self.data = doc_field.read
    else
      content = XmlContent.new
      content.name = self.name
      content.data = doc_field.read
      self.xml_content = content
    end
  end
end 

  既然定义了 XML_CONTENTS 和 DOCUMENTS 表的模型,就必须修改视图来处理上载和显示功能。更新了上载功能和列出文档的视图,允许显式地选择要显示的模型属性(列)。

  /app/views/documents/list.rhtml 实现这种显式的列选择:

  清单 8. /app/views/documents/list.rhtml

<table cellpadding="0" cellspacing="0">
  <tr>
   <th>ID</th>
   <th>Document name</th>
   <th>Subject</th>
   <th>Shared by</th>
   <th>Size</th>
   <th>Update at</th>
   <th>Platform</th>
   <th></th>
   <th></th>
   <th></th>
  </tr>
  <% @documents.each_with_index do |document,i| %>
    <% row_class = i%2 ==0 ? "even" : "odd" %>
    <tr class="<%=row_class%>">
    <td><%= document.id %></td>
    <td><%= document.name %></td>
  <% if document.subject %>
    <td><%= link_to "#{document.subject.name}",
                     :controller => 'subjects', :action => 'list'  %></td>
  <% else %>
    <td></td>
  <% end %>
  <% if document.user %>
    <td><%= link_to "#{document.user.userid}",
                     :controller => 'users', :action => 'list'  %></td>
  <% else %>
    <td></td>
  <% end %>
    <td><%= number_to_human_size( document.size ) %></td>
    <td><%= document.updated_at.strftime("%d/%m/%Y %I:%M%p") %></td>
    <td><%= document.platform %></td>
    <td><%= link_to 'Show', :action => 'show', :id => document %></td>
    <td><%= link_to 'Edit', :action => 'edit', :id => document %></td>
    <td><%= link_to 'Remove', { :action => 'destroy', :id => document },
                     :confirm => 'Are you sure?', :method => :post %></td>
    </tr>
  <% end %>
</table>

  然后,对控制器做以下更新来处理 XML 数据的文档显示功能。这些代码添加在 /app/controllers/documents_controller.rb 中。

  清单 9. documents_controller.rb

 def show
  @document = Document.find(params[:id])
  doc_type = @document.content_type
  unless doc_type.include?('text/xml')
    doc_content = @document.data
  else
    doc_content = @document.xml_content.data
  end
  send_data(doc_content,
            :filename => @document.name,
            :type => doc_type,
            :disposition => "inline")
end

  还要做以下更新来支持 XML 文档上载,您可能注意到了主题和用户关系处理的文档实现。

  清单 10. documents_controller.rb

 def upload
  if params[:document][:uploaded_doc].to_s.empty?
    flash[:notice] = "Please provide a file for upload"
    redirect_to(:action => "new" )
  else
    @document = Document.new(params[:document])
    @subject = params[:subject_name] && params[:subject_name].empty? ?
               Subject.new :
               Subject.find_by_name(params[:subject_name])

    Document.transaction do
      User.find(session[:user_id]).documents << @document
      @subject.documents << @document
      @subject.size = @subject.documents.size
      if @subject.new_record?
        @subject.name = params[:subject][:name]
        @subject.tag = params[:subject][:tag]
        @subject.description = params[:subject][:description]
        @subject.save
      end

      if @document.save
        flash[:notice] = "Document #{@document.name} successfully created."
        if @document.subject.subscriptions
          SubscriptionMailer.deliver_notify(@document)
        end
        redirect_to :action => 'list'
      else
        render :action => 'new'
      end
    end
  end

  下面的 图 1 描述了在执行上面的迁移步骤之后,Team Room 中不同模型之间的关联。

  图 1. 修改之后不同模型之间新的关联

  数据库模式图

  将 XML 市场营销数据上载到 Team Room

  注:只能使用 IMPORT 命令导入格式良好的 XML 文档。

  注:可以使用以下命令删除 XML 模式:

  drop xsrobject teamroom.marketinfo

相关搜索:
关注此文读者还看过
热门关注
特别推荐
文章排行
本周
本月
最近更新
关于我们|About us|网站律师|天极服务|电子杂志|RSS订阅|加入我们|网站地图
TMG
Copyright (C) 1999-2009 Chinabyte.com, All Rights Reserved 版权所有 天极网络
商务联系、网站内容、合作建议:010-82657868
版权声明 在线提交意见反馈 渝ICP证B2-20030003号
经营性网站备案信息 网警备案 中国网站排名
天极传媒:天极网|比特网|IT专家网|IT商网|52PK游戏网|IT分众