`
wuhuizhong
  • 浏览: 688728 次
  • 性别: Icon_minigender_1
  • 来自: 中山
社区版块
存档分类
最新评论

使用Rails关联创建多对多关系

    博客分类:
  • ROR
阅读更多

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

 

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

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

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

一、连接表:简单的关联

 表:

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

 

 模型:

class Dancer < ActiveRecord::Base
  has_and_belongs_to_many :movies
end

class Movie < ActiveRecord::Base
  has_and_belongs_to_many :dancers
end

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

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

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

 

模型:

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 *'

分享到:
评论

相关推荐

    Rails 101 入门电子书

    - 实现关联关系。 - 创建PostsController控制器。 - 实现CRUD操作。 - **高级技巧**: - 使用before_action简化代码。 #### 十、练习作业3-为Group与Post加入使用者机制 - **目标**: - 添加用户身份验证。 - *...

    Rails入门教程一(翻译).pdf

    模型部分会涉及ActiveRecord的生命周期,包括创建、读取、更新和删除(CRUD)操作,以及关联(Associations)如一对一、一对多、多对多等,这些关联让数据间的复杂关系得以轻松管理。 此外,教程还会涉及表单...

    Rails 101S

    - **Active Record Associations**:深入探讨Active Record的关联关系管理,如一对一、一对多等关联类型。 #### 总结 《Rails 101S》不仅是一本适合新手入门的教程,也是进阶开发者的好帮手。通过实践这些基础知识...

    Rails项目源代码

    在这个项目中,`User`和`Image`模型可能会与数据库中的相应表关联,通过定义属性和关系,如`has_many :images`表示一个用户可以拥有多个图片。 5. **路由配置**: Rails的路由系统将URL映射到控制器的行动上,如`/...

    rails敏捷开发的购物车系统

    创建购物车模型(Cart)和商品模型(Product),定义它们之间的关系,如多对多关系,通过一个关联表记录每个购物车包含的商品及其数量。使用`has_and_belongs_to_many`或`has_many :through`关联来实现这一关系。 ...

    免费下载!!! ruby on rails -- redmine 项目的表结构详细说明以及关联关系

    这些表之间的关联关系构建了 Redmine 的核心功能,例如,`users` 与 `issues` 之间的关联允许追踪问题的所有者和分配者,`changesets` 与 `changes` 之间的关联则反映了代码仓库的变更历史。理解这些表结构对于定制 ...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    - **定义**:关联是指定义模型之间的关系,如一对一、一对多等。 - **示例**:例如,在博客系统中,一篇文章可以有多个评论,这就是典型的“一对多”关系。 #### 四、查询 - **方法**:使用Active Record的方法来...

    关于Rails中的表关联的程序

    这种关联用于表示两个模型之间多对多的关系。比如,用户(User)和角色(Role)之间可能存在HABTM关系,用户可以有多个角色,角色也可以被多个用户拥有。在两个模型中添加相同的join表(如`users_roles`): ```ruby ...

    使用RSpec 测试Rails 程序.pdf

    4. **生成器**:使用`rails generate rspec:install`命令来初始化RSpec,并创建必要的目录结构和初始文件。 #### 三、模型测试 - **分析模型测试**:了解模型的基本结构,包括属性、关联关系、验证规则等。 - **...

    rails本地安装包完整版

    7. **activerecord-2.1.0.gem**:ActiveRecord是Rails中的ORM(对象关系映射)库,负责将数据库表映射为Ruby类,使得开发者可以通过面向对象的方式来操作数据库,而无需编写SQL语句。 这个本地安装包特别适合网络...

    Ruby on Rails 指南 v5.0.1 中文版

    - **联结表**:讲解如何处理多对多关联关系。 - **及早加载关联**:介绍如何预先加载关联对象以避免N+1查询问题。 - **作用域**:解释如何定义作用域来封装常用的查询逻辑。 - **动态查找方法**:介绍如何使用动态...

    rails查询学习笔记

    在Rails中,数据库查询主要通过ActiveRecord来实现,这是一个强大的ORM(对象关系映射)工具,能够将数据库表与Ruby类关联,简化数据操作。 描述中虽然没有具体信息,但我们可以推测这可能是一篇关于Rails中查询...

    Advanced Rails

    "Advanced Rails" 涵盖了Rails开发中的高级主题和技术,是Ruby on Rails学习进阶的重要资源,尤其适合已经对基础Rails有一定了解的开发者。 在Web开发领域,Rails以其高效、简洁的代码和“约定优于配置”的哲学吸引...

    使用 rails进行敏捷开发(第三版)

    5. **ActiveRecord关联**:讲解不同类型的关联(一对一、一对多、多对多),以及如何通过关联进行数据查询。 6. **控制器与动作**:说明如何创建控制器,定义动作,以及处理HTTP请求。 7. **视图与模板引擎**:...

    Ruby on Rails 4 Tutorial 中文版

    ActiveRecord的关联功能也是重点,它允许你轻松处理多对一、一对一、多对多的关系,简化了数据库操作。同时,你会学到如何使用Rails的验证机制来保证数据的完整性和一致性。 在部署方面,Rails 4支持Heroku、...

    Rails 3 in Action

    5. **ActiveRecord**:详述了ActiveRecord是如何作为对象关系映射(ORM)层工作的,包括模型定义、关联关系(如has_many、belongs_to等)、数据库迁移以及查询方法。 6. **测试驱动开发(TDD)**:Rails强调TDD,书...

    [Rails 常用插件简介]CRUD Generator 2

    比如,你可能需要自定义验证规则、关联关系、或者视图中的样式和布局。理解生成的代码结构,能够帮助你更高效地进行定制。 **5. CRUD Generator 2的优缺点** 优点: - 快速生成基本的CRUD功能,节省开发时间。 - ...

    rails-1.0.0

    开发者可以定义属性、关联(如一对一、一对多、多对多)、以及验证规则,确保数据的完整性和一致性。 3. **ActionController**:控制器层处理HTTP请求,并将数据传递给视图进行渲染。它也负责调用模型来获取或更新...

Global site tag (gtag.js) - Google Analytics