Rails ActiveRecord数据库关系n:n
如图所示,在demo数据库中有assemblies和parts两张表。一个assembly有多个part,一个part也拥有多个assembly,是一个n:n关系。
- 建立数据表
由于n:n的关系是以中间表的形式表达的,所以需要创建图示中的三张表assemlies, parts和中间表assemlies_part。
$ rails g model assembly name:string
$ rails g model part part_number:string
$ rails g migration CreateAssembliesAndParts
编辑db/migrate/目录下新建的xxxx_create_assemblies_and_parts.rb文件,在该文件中定义中间表:
1 2 3 4 5 6 7 8 |
|
注意,该表包含n:n的两端表的主键,且自身不使用主键,故:id=>false。
另外,该中间表的表名是“assemblies_part“,以中间的下划线连接两张表,并且按照字母顺序小在前字母顺序大的在后排列,如果创建”part_assemlies“表,则rails可能找不到该中间表。
实际上,rails是以string的”<“操作来比较单词的,所以,如果不确定哪个表在前哪个在后,可以使用该操作符确定一下再创建表。比如有两张表”devil_x“和”devilx”(为什么会有人取这么奇怪的表名呢),那就需要自己来确认一下中间表的表名:
irb(main):002:0> 'devil_x'<'devilx'
=> true
所以,中间表的表名应该是“devil_x_devilx”。
最后,确认创建数据表:
$ rake db:migrate
- 修改model,添加关系
在关系的两端都需要添加has_and_belongs_to_many。
1 2 3 |
|
1 2 3 |
|
- 操作关系
在n:n关系的两端都添加了如下方法:
collection(force_reload=false)
collection<<(object, ...)
collection.delete(object, ...)
collection = objects
collection_singular_ids
collection_singular_ids = ids
collection.clear
collection.empty?
collection.size
collection.find(...)
collection.where(...)
collection.exists?(...)
collection.build(attributes = {})
collection.create(attributes = {})
可以看到,添加的方法和has_many关系添加的方法相同,所以就不再重复介绍使用方法。
- 特殊多对多关系,多态
还是以Picture,Employee,Product为例,Picture和Employee,Product都是多对多的关系,首先创建数据表。
$ rails g model picture
$ rails g model picture_box box_id:integer box_type:string picture_id:integer
$ rails g model employee
$ rails g model product
修改model:
1 2 3 4 |
|
1 2 3 4 |
|
1 2 3 4 5 |
|
1 2 3 4 |
|
所有拥有picture的model中,都在其has_many关系中添加了选项:as=>:box,而picture的model中has_many关系添加了:polymorphic=>true选项。