`
hot88zh
  • 浏览: 179071 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

has_many :through

阅读更多
原E文地址:http://blog.hasmanythrough.com/2006/04/20/many-to-many-dance-off



我已注意到使用 Rails 关联在创建多对多关系的两种方式上有些混乱。出现混乱是可以理解的,因为has_many :through 还有些新,写它的文章并不多。

Has_and_belongs_to_many 出现的较早,确定的角色与资料超出了你为什么使用多对多关系的假设。事实上,许多人似乎并没有抓住本质上的区别。

就像我们从观看经典影片所学到的,告诉我们两个预期选择之间的区别最好方式是它们的舞蹈。你得观察每个人的表演。那么我们必须在两者之间选择哪个演员呢?

一、连接表:简单的关联

表:

Ruby代码
create_table "dancers_movies", :id => false do |t|  
  t.column "dancer_id", :integer, :null => false 
  t.column "movie_id",  :integer, :null => false 
end 

create_table "dancers_movies", :id => false do |t|
  t.column "dancer_id", :integer, :null => false
  t.column "movie_id",  :integer, :null => false
end

模型:

Ruby代码
class Dancer < ActiveRecord::Base  
  has_and_belongs_to_many :movies 
end 
 
class Movie < ActiveRecord::Base  
  has_and_belongs_to_many :dancers 
end 

class Dancer < ActiveRecord::Base
  has_and_belongs_to_many :movies
end

class Movie < ActiveRecord::Base
  has_and_belongs_to_many :dancers
endhas_and_belongs_to_many 关联的设置很简单。连接表只有被连接模型的外键,没有主键或其它属性。(其它属性使用暂时的 push_with_attributes 来支持,但该特征被废弃了。)此处没有给连接表使用的模型类。

二、连接模型:富关联(Rich Associations)
表:

Ruby代码
create_table "appearances", do |t|  
  t.column "dancer_id",      :integer, :null => false 
  t.column "movie_id",       :integer, :null => false 
  t.column "character_name", :string 
  t.column "dance_numbers",  :integer 
end 

create_table "appearances", do |t|
  t.column "dancer_id",      :integer, :null => false
  t.column "movie_id",       :integer, :null => false
  t.column "character_name", :string
  t.column "dance_numbers",  :integer
end

模型:

Ruby代码
class Appearance < ActiveRecord::Base  
  belongs_to :dancer 
  belongs_to :movie 
end 
 
class Dancer < ActiveRecord::Base  
  has_many :appearances, :dependent => true 
  has_many :movies, :through => :appearances 
end 
 
class Movie < ActiveRecord::Base  
  has_many :appearances, :dependent => true 
  has_many :dancers, :through => :appearances 
end 

class Appearance < ActiveRecord::Base
  belongs_to :dancer
  belongs_to :movie
end

class Dancer < ActiveRecord::Base
  has_many :appearances, :dependent => true
  has_many :movies, :through => :appearances
end

class Movie < ActiveRecord::Base
  has_many :appearances, :dependent => true
  has_many :dancers, :through => :appearances
end

has_many :through 关联对这个简单例子来说很容易设定的,但是当使用其它特征如 polymorphism 时要有些技巧。用于连接模型的表有个主键并包含了类似其它模型的属性。

三、Checking out the moves

下面是对两种操作基本特征的比较

关联Association has_and_belongs_to_many has_many :through
AKA habtm关联 through association遍历关联
结构Structure          连接表(Join Table) 连接模型(Join Model)
主键Primary Key            no                    yes
富关联Rich Association      no                    yes
代理集合Proxy Collection     yes                   no
Distinct 选择                  yes                   yes
自引用Self-Referential       yes                  yes
早期加载Eager Loading        yes                   yes
多态性Polymorphism           no                   yes
多向连接N-way Joins          no                    yes


该表格内包含了很多东西,现在我们分别看一下:

(1)、结构:
has_and_belongs_to_many 使用了简单的连接表,表的每一行记录只有两个外键。没有为连接表使用模型类的连接记录从不会被直接访问。
has_many :through 更新连接表为一个完整的模型。它使用一个模型类来表现表内的条目。

(2)、主键:
连接表没有主键。我听说一些人,如从外键对创建一个主键,但 Rails 从不为任何东西使用主键。我不能肯定你为什么要得到创建的主键,虽然它可能依据你数据库给你一些性能上的好处。 (我不是一个 DBA ,所以对于主键不想说得太多。)
连接模型有键,就像其它模型。这意味着你可以直接地访问及管理记录。

(3)富关联:
在 Rails 1.1 以前,你使用 push_with_attributes 来存储额外的属性到你的 habtm 连接表内。这样做会带来很多问题,包括随后不能更新属性。Push_with_attributes 现在不再使用了。如果你希望一个带有额外属性的富关联的话,使用连接模型。

(4)、代理集合:
使用 habtm 的一个好处是,关联是个代理集合。这意味着你可以使用关联的 << 方法在连接表内创建条目,就像 has_many 关联。因为连接模型记录有这些额外属性,所以用同样方式来自动创建连接表条目会更复杂。所以你必须手工创建连接模型条目。(更完整的解释,可参阅我的 Why aren't join models proxy collections? 文章。)

(5)、Distinct 选择:
有时候,连接表(或模型)在同样的记录之间可能有多个引用。例如,一个人可能是一本书的作者及插图绘制者。如果你有多个引用,数据库会返回给你所有与你查询相关多条记录。选项 :uniq 告诉关联过滤重复的对象,以便你只得到每个记录的一条显示。这类似于在 SQL 中使用 DISTINCT 关键字,但这是在 Ruby 内而不是数据库内移除重复发生的记录。这篇文章原只由 habtm 支持的 :uniq 才能查到,但现在通过 through 关联也可以查到。

(6)、自引用:
Habtm 与 through 关联都可是自引用的。Users 的朋友用户就是一个自引用关系的例子。你可以通过在关联上使用带有 :foreign_key 与 :association_foreign_key 选项的 habtm 来完成。同样也可以使用 through 关联,因为它的做法不太明显,所以稍后我会写出如何处理它。

(7)、早期加载
Habtm 与 through 关联都通过 :include 选项来支持被关联对象的早期加载。

(8)、多态性:
连接模型与 through 关联可以用 polymorphic 模型类型工作。

(9)、多向连接
一个 habtm 关联只可以连接两个模型。但有时候你需要表现多个模型的关联。例如登记的可能是一位飞行家,一个乘客,及一个座位的分配。使用 through 关联,你可以创建一个连接模型,它连接你需要的多个模型。技巧部分是如何构建可方便地得到被关联对象的查询。

四、And the winner is...

has_and_belongs_to_many 的使用范围狭小。但 has_many :through 则很广泛。

Seriously, there's no way to pick a winner here. Like any engineering decision, choosing a join table or a join model is a matter of picking the right tool for the job (or the right dancer for the part). Now that you've seen our players go head to head, you can make a better choice about who should get that part.



五、回帖部分:

1、David on 2006年4月21日

关于 distinct 选择 ---- 我认为你可以附加 :select 'DISTINCT *' 给关联,类似于: has_many foos, :through => bars, :select 'DISTINCT *'
分享到:
评论

相关推荐

    many-to-many-through:这是使用has_many的许多示例教程

    has_many:通过 这是关于如何使用has_many :throght创建多对多关联的完整示例has_many :throght在此示例中,我使用staff模型和client模型,其中人员有很多客户,而客户有很多员工 操作说明 在下面的终端中输入 $ ...

    many-many-through

    通过表多对多 最简单的经验法则是,如果需要将关系模型作为独立实体使用,则应设置has_many :through关系。 示例包括: ... has_many :movies, through: :subscriptions end class Movie &lt; Applicati

    dpl_has_many_through_hwr:DPL作业复习-has_many_through

    入门项目 设置和运行步骤 ...cd project-name bundle install 在database.yml中,将数据库what_ever_you_named_your_start_project的名称更改为project-name rails db:create db:migrate db:seed ...

    Ruby on Rails中的ActiveRecord编程指南

     偏好 has_many :through 胜于 has_and_belongs_to_many。 使用 has_many :through 允许在 join 模型有附加的属性及验证   # 使用 has_and_belongs_to_many class User &lt; ActiveRecord::Base has_and_...

    amoeba:Ruby宝石,允许复制ActiveRecord对象及其关联的子对象,可通过模型上的DSL配置

    has_many :through has_and_belongs_to_many 一个简单的DSL,用于配置要复制的字段。 DSL可以应用于您的Rails模型或即时使用。 支持STI(单表继承)子代继承其父变形虫设置。 多种配置样式,例如包含,排除和不

    Ruby-Rails-Donut-Review-App

    您的模型必须: •包括至少一个has_many,至少一个belongs_to和至少两个has_many:through关系•包括用has_many:through关联实现的多对多关系。 联接表必须包含一个用户可提交的属性-也就是说,该应用程序的用户...

    加入有趣的轨道v-000

    下一步是在这三个模型之间建立一个has_many :through关系,以便我们可以跟踪谁在开车谁。 它将像这样工作: Taxi -&lt; Rides&gt;- Passengers 这样,出租车可以有很多乘客,而乘客可以有很多出租车! 每个表只有一个...

    query_methods_extend

    has_many :books , through : :categories end // Store ( id : integer , address : string ) class Category &lt; ActiveRecord :: Base belongs_to :store has_many :books end // Category ( id : integer , ...

    displaying-has-many-through-rails-onl01-seng-pt-032320

    对我们来说幸运的是has_many, through Active Record和has_many, through来显示这种类型的数据的界面也很容易。 课 has_many,通过 假设您正在制作博客,并希望使用户能够注册并评论您的帖子。 帖子和评论之间有...

    SinatraStreetFighter:欢迎使用我简化的Street Fighter模拟版本。 您可以选择一个角色,添加战斗动作以及史诗般的战斗开始的最后阶段!

    特征 楷模用户,角色,移动,舞台用户has_many:字符字符belongs_to :用户字符has_many :动作字符has_many :stages, through: ::moves 阶段has_and_belongs_to_many :移动阶段has_many :characters, ...

    Courier:用于将 JSON 资源同步到核心数据的 Rubymotion 包装器

    信使 用于将 JSON 资源同步到核心数据的 Rubymotion 包装器。 -- ###Setup Gemfile gem 'afmotion' ... bundle exec rake pod:... has_many :players , through : [ :teams , :players ] attr_accessor :unpersis

    polo:Polo遍历您的数据库并创建示例快照,因此您可以在开发中使用现实世界的数据

    马球 Polo遍历您的数据库并创建示例快照,因此您可以在任何环境中使用真实数据。 Polo接受一个ActiveRecord::Base种子对象,并遍历所有列入白名单的ActiveRecord::... has_many :ingredients , through : :rec

    displaying-has-many-through-rails-v-000

    对我们来说幸运的是has_many, through Active Record和has_many, through来显示这种类型的数据的界面也很容易。 课 has_many,通过 假设您正在制作博客,并希望使用户能够注册并评论您的帖子。 帖子和评论之间有...

    trades:Ruby on Rails-has_many_through高级关联

    自述文件 该自述文件通常会记录启动和运行应用程序所需的所有步骤。 您可能要讲的内容: Ruby版本 系统依赖 配置 数据库创建 数据库初始化 如何运行测试套件 服务(作业队列,缓存服务器,搜索引擎等) ...

    has-many-through-selection:Rails 5.1示例应用程序,用于使用复选框管理组成员

    有很多通过选择应用程序 在这个Rails 5.1示例应用程序中,我们可以使用一个带有复选框的表单来管理组及其成员。 设置 $ bin/setup $ bin/rails server 描述 我们正在使用Group.accepts_nested_attributes_for :...

    atlas:Elixir的对象关系映射器

    通过以下方式添加模型关系,即belongs_to , has_many , has_many through: 其他SQL适配器 模式迁移 用法示例: defmodule User do use Atlas . Model @table :users @primary_key :id field :id , :integer...

    paper_trail-association_tracking:PaperTrail gem插件,用于跟踪和确定关联

    PaperTrail-AssociationTracking可以还原三种类型的关联:Has-One,Has-Many和Has-Many-Through。 当关联记录更改时,它将在version_associations表中存储其他信息,以关联关联版本和模型版本。 验证模型时,它将...

    cfcalendar-backend

    has_many导师through任命 导师 has_many预约 has_many through预约的学生 约定 belongs_to学生 belongs_to导师 模型::变量 用户(学生和导师) 姓名 电子邮件 时区 约定 标题 学生卡 mentor_id 描述 状态[待审核,...

    activerecord-associations-in-v-000

    使用Active Record迁移和方法来构建域模型,该域模型通过has-many / belongs-to和多对多(或has-man-through)关系来关联类。 什么是活动记录协会? 我们已经知道我们可以构建我们的类,使它们彼此关联。 我们也...

    activerecord-associations-intro-onl01-seng-ft-090820

    使用Active Record迁移和方法来构建域模型,该域模型通过has-many / belongs-to和多对多(或has-man-through)关系来关联类。 什么是活动记录协会? 我们已经知道我们可以构建我们的类,使它们彼此关联。 我们也...

Global site tag (gtag.js) - Google Analytics