多态关联--异构对象聚合技术
将不同的类(表)聚合(关联)起来
不同的类
表现不同,但是具有某些
共同的特征
下面来举一个例子,对于三个不同的类, Article, Sound, Image,他们的类型不同,表现形式不同,也就是对应表的结构不同:
创建一个rails应用
rails polymorphic
新建三个模型类Article, Sound, Image,对应的数据迁移内容:
#articles
create_table :articles do |t|
t.column :content, :text
t.column :content, :text
t.column :publisher, :string
end
#sounds
create_table :sounds do |t|
t.column :content, :binary
t.column :content, :binary
end
#images
create_table :images do |t|
t.column :content, :binary
t.column :content, :binary
t.column :description, :text
end
end
而这三者有些共同的特征:
有名称,获得日期等其他的基本信息,通过一个目录表以便查找对应的数据内容。
#catalog_entries
create_table :catalog_entries do |t|
t.column :name, :string
t.column :acquired_at, :datetime
t.column :resource_id, :integer
t.column :resource_type, :string
end
t.column :name, :string
t.column :acquired_at, :datetime
t.column :resource_id, :integer
t.column :resource_type, :string
end
在目录这个表中,通过resource_id和resource_type共同组成的外键来决定数据内容。给这个外键起名叫resource
在CatalogEntry中定义:
class CatalogEntry < ActiveRecord::Base
belongs_to :resource, :polymorphic => true
end
belongs_to :resource, :polymorphic => true
end
在Article类中定义:
class Article < ActiveRecord::Base
has_one :catalog_entry, :as => :resource
end
has_one :catalog_entry, :as => :resource
end
在Sound类中定义:
class Sound < ActiveRecord::Base
has_one :catalog_entry, :as => :resource
end
has_one :catalog_entry, :as => :resource
end
在Image类中定义:
class Image < ActiveRecord::Base
has_one :catalog_entry, :as => :resource
end
has_one :catalog_entry, :as => :resource
end
ruby script/console
在最后c.save!执行之后,articles表和catalog_entries表中才有数据写入。
articles表的内容:
catalog_entries表内容:
在终端中做查询:
resource=cat.resource得到的是cat这条目录对应的类的对象!amazing`ha~
现在清空数据空,插入代表所有这三种资源的数据:
>>
c=CatalogEntry.new(:name=>'Article one', :acquired_at=>Time.now)
=> #<CatalogEntry id: nil, name: "Article one", acquired_at: "2008-08-31 15:06:4
9", resource_id: nil, resource_type: nil, created_at: nil, updated_at: nil>
>> c.resource=Article.new(:content=>"This is my new article", :publisher=>"tyut"
)
=> #<Article id: nil, content: "This is my new article", publisher: "tyut", crea
ted_at: nil, updated_at: nil>
>> c.save!
=> true
>> c=CatalogEntry.new(:name=>'Image One', :acquired_at=>Time.now)
=> #<CatalogEntry id: nil, name: "Image One", acquired_at: "2008-08-31 15:08:07"
, resource_id: nil, resource_type: nil, created_at: nil, updated_at: nil>
>> c.resource=Image.new(:content=>"Some binary data")
=> #<Image id: nil, content: "Some binary data", description: nil, created_at: n
il, updated_at: nil>
>> c.save!
=> true
>> c=CatalogEntry.new(:name=>'Sound One', :acquired_at=>Time.now)
=> #<CatalogEntry id: nil, name: "Sound One", acquired_at: "2008-08-31 15:09:22"
, resource_id: nil, resource_type: nil, created_at: nil, updated_at: nil>
>> c.resource=Sound.new(:content=>"more binary data")
=> #<Sound id: nil, content: "more binary data", created_at: nil, updated_at: ni
l>
>> c.save!
=> true
=> #<CatalogEntry id: nil, name: "Article one", acquired_at: "2008-08-31 15:06:4
9", resource_id: nil, resource_type: nil, created_at: nil, updated_at: nil>
>> c.resource=Article.new(:content=>"This is my new article", :publisher=>"tyut"
)
=> #<Article id: nil, content: "This is my new article", publisher: "tyut", crea
ted_at: nil, updated_at: nil>
>> c.save!
=> true
>> c=CatalogEntry.new(:name=>'Image One', :acquired_at=>Time.now)
=> #<CatalogEntry id: nil, name: "Image One", acquired_at: "2008-08-31 15:08:07"
, resource_id: nil, resource_type: nil, created_at: nil, updated_at: nil>
>> c.resource=Image.new(:content=>"Some binary data")
=> #<Image id: nil, content: "Some binary data", description: nil, created_at: n
il, updated_at: nil>
>> c.save!
=> true
>> c=CatalogEntry.new(:name=>'Sound One', :acquired_at=>Time.now)
=> #<CatalogEntry id: nil, name: "Sound One", acquired_at: "2008-08-31 15:09:22"
, resource_id: nil, resource_type: nil, created_at: nil, updated_at: nil>
>> c.resource=Sound.new(:content=>"more binary data")
=> #<Sound id: nil, content: "more binary data", created_at: nil, updated_at: ni
l>
>> c.save!
=> true
得到表的内容:
artists:
images:
sounds:
catalog_entries:
从第三张表中可以看出,catalog_entry是利用resource_id和resource_type来共同决定资源定位的。
下面遍历catalog_entries表:
>> CatalogEntry.find(:all).each do |c|
?> puts "#{c.name}: #{c.resource.class}"
>> end
?> puts "#{c.name}: #{c.resource.class}"
>> end
输出结果:
Article one: Article
Image One: Image
Sound One: Sound
Article one: Article
Image One: Image
Sound One: Sound
本文转自 fsjoy1983 51CTO博客,原文链接:http://blog.51cto.com/fsjoy/96426,如需转载请自行联系原作者