rails 两表关联查询

by Haley Mnatzaganian

通过海利·姆纳扎卡尼安

Rails中的单表继承与多态关联:找到适合您的方法 (Single-table inheritance vs. polymorphic associations in Rails: find what works for you)

If you’ve ever created an application with more than one model, you’ve had to think about what type of relationships to use between those models.

如果创建的应用程序具有多个模型,则必须考虑在这些模型之间使用哪种类型的关系。

As an application’s complexity grows, it can be difficult to decide which relationships should exist between your models.

随着应用程序复杂性的增加,可能很难确定模型之间应该存在哪些关系。

A situation that frequently comes up is when several of your models need to have access to the functionality of a third model. Two methods that Rails gives us to deal with this event are single-table inheritance and polymorphic association.

经常出现的情况是您的多个模型需要访问第三个模型的功能。 Rails给我们提供了两种方法来处理此事件: 单表继承多态关联。

In Single-Table Inheritance (STI), many subclasses inherit from one superclass with all the data in the same table in the database. The superclass has a “type” column to determine which subclass an object belongs to.

在单表继承(STI)中,许多子类都从一个超类继承而来,所有数据都在数据库的同一表中。 超类具有“类型”列,用于确定对象属于哪个子类。

In a polymorphic association, one model “belongs to” several other models using a single association. Each model, including the polymorphic model, has its own table in the database.

多态关联中 ,一个模型使用单个关联“属于”其他几个模型。 每个模型(包括多态模型)在数据库中都有自己的表。

Let’s take a look at each method to see when we would use them.

让我们看一下每种方法,看看何时使用它们。

单表继承 (Single-Table Inheritance)

A great way to know when STI is appropriate is when your models have shared data/state. Shared behavior is optional.

知道何时使用STI的一种好方法是您的模型何时共享数据/状态 。 共享行为是可选的。

Let’s pretend we are creating an app that lists different vehicles that are for sale at a local dealership. This dealership sells cars, motorcycles, and bicycles.

假设我们正在创建一个应用程序,其中列出了要在当地经销商处出售的不同车辆。 该经销店销售汽车,摩托车和自行车。

(I know dealerships don’t sell bicycles, but bear with me for a minute — you’ll see where I’m going with this.)

(我知道经销商不销售自行车,但请耐心等待一分钟-您会看到我要去的地方。)

For each vehicle, the dealership wants to track the price, color, and whether the vehicle was purchased. This situation is a perfect candidate for STI, because we are using the same data for each class.

对于每辆车,经销商都希望跟踪价格,颜色以及是否购买了该车。 这种情况非常适合STI,因为我们为每个类别使用相同的数据。

We can create a superclass Vehicle with the attributes for color, price, and purchased. Each of our subclasses can inherit from Vehicle and can all get those same attributes in one fell swoop.

我们可以创建具有颜色,价格和购买属性的超类Vehicle 。 我们的每个子类都可以从Vehicle继承,并且可以一次获得所有相同的属性。

Our migration to create the vehicles table might look like this:

我们创建车辆表的迁移可能如下所示:

class CreateVehicles < ActiveRecord::Migration[5.1]  def change                               create_table :vehicles do |t|                                   t.string :type, null: false                               t.string :color                                   t.integer :price                                  t.boolean :purchased, default: false                                                          end                           end                       end

It is important that we create the type column for the superclass. This tells Rails that we are using STI and want all the data for Vehicle and its subclasses to be in the same table in the database.

创建超类的type列很重要。 这告诉Rails我们正在使用STI,并且希望Vehicle及其子类的所有数据都在数据库的同一表中。

Our model classes would look like this:

我们的模型类如下所示:

class Vehicle < ApplicationRecordend
class Bicycle < Vehicleend
class Motorcycle < Vehicleend
class Car < Vehicleend

This setup is great because any methods or validations in the Vehicle class are shared with each of its subclasses. We can add unique methods to any of the subclasses as needed. They are independent of each other and their behavior is not shared horizontally.

该设置非常好,因为Vehicle类中的任何方法或验证都与其每个子类共享。 我们可以根据需要向任何子类添加唯一方法。 它们彼此独立,并且它们的行为不是水平共享的。

Additionally, since we know that the subclasses share the same data fields, we can make the same calls on objects from different classes:

另外,由于我们知道子类共享相同的数据字段,因此我们可以对来自不同类的对象进行相同的调用:

mustang = Car.new(price: 50000, color: red)harley = Motorcycle.new(price: 30000, color: black)
mustang.price=> 50000
harley.price=> 30000

增加功能 (Adding functionality)

Now let’s say the dealer decides to collect some more information about the vehicles.

现在,假设经销商决定收集有关车辆的更多信息。

For Bicycles, she wants to know if each bike is a road, mountain, or hybrid bike. And for Cars and Motorcycles, she wants to keep track of the horsepower.

对于Bicycles ,她想知道每辆自行车是公路,山地还是混合动力自行车。 对于CarsMotorcycles ,她想跟踪马力。

So we create a migration to add bicycle_type and horsepower to the Vehicles table.

因此,我们创建了一个迁移,以将bicycle_typehorsepower添加到Vehicles表中。

All of a sudden, our models don’t perfectly share data fields anymore. Any Bicycle object will not have a horsepower attribute, and any Car or Motorcycle will not have a bicycle_type (hopefully — I’ll get to this in a moment).

突然之间,我们的模型不再完美地共享数据字段。 任何“ Bicycle对象都不会具有horsepower属性,任何“ Car或“ Motorcycle都不会具有bicycle_type (希望,我稍后bicycle_type到)。

Yet every bicycle in our table will have a horsepower field, and every car and motorcycle will have a bicycle_type field.

然而,我们餐桌上的每辆自行车都会有一个horsepower场,每辆汽车和摩托车都会有一个bicycle_type场。

This is where things can get sticky. A few issues can arise in this situation:

这是事情变得棘手的地方。 在这种情况下可能会出现一些问题:

  1. Our table will have a lot of null values (nil in Ruby’s case) since objects will have fields that don’t apply to them. These nulls can cause problems as we add validations to our models.

    我们的表将具有很多空值(在Ruby中nil ),因为对象将具有不适用于它们的字段。 当我们向模型添加验证时,这些nulls可能会导致问题。

  2. As the table grows, we can run into performance costs when querying if we don’t add filters. A search for a certain bicycle_type will look at every item in the table— so not only Bicycles, but Cars and Motorcycles also.

    随着表的增长,如果不添加过滤器,我们可能会在查询中遇到性能成本问题。 搜索某个bicycle_type将查看表中的每个项目 ,因此不仅是Bicycles ,还包括CarsMotorcycles

  3. As is, there is nothing stopping a user from adding “inappropriate” data to the wrong model. For example, a user with some know-how could create a Bicycle with a horsepower of 100. We would need validations and good app design to prevent the creation of an invalid object.

    照原样,没有什么可以阻止用户将“不适当的”数据添加到错误的模型中。 例如,具有某些专业知识的用户可以创建horsepower为100的Bicycle 。我们需要进行验证和良好的应用设计,以防止创建无效的对象。

So, as we can see, STI does have some flaws. It is great for applications where your models share data fields and aren’t likely to change.

因此,正如我们所看到的,STI确实存在一些缺陷。 对于您的模型共享数据字段并且不大可能更改的应用程序来说,它非常有用。

STI PROS:

STI优点:

  • Simple to implement易于实施
  • DRY — saves replicated code using inheritance and shared attributesDRY-使用继承和共享属性保存复制的代码
  • Allows subclasses to have own behavior as necessary允许子类根据需要拥有自己的行为

STI CONS:

STI缺点:

  • Doesn’t scale well: as data grows, table can become large and possibly difficult to maintain/query无法很好地扩展:随着数据的增长,表可能会变得很大,并且可能难以维护/查询
  • Requires care when adding new models or model fields that deviate from the shared fields添加新模型或偏离共享字段的模型字段时需要格外小心
  • (conditional) Allows creation of invalid objects if validations are not in place(有条件的)如果验证不到位,则允许创建无效的对象
  • (conditional) Can be difficult to validate or query if many null values exist in table(有条件)可能难以验证或查询表中是否存在许多空值

多态关联 (Polymorphic Associations)

With polymorphic associations, a model can belong_to several models with a single association.

使用多态关联,一个模型可以belong_to一个关联的多个模型。

This is useful when several models do not have a relationship or share data with each other, but have a relationship with the polymorphic class.

当几个模型没有关系或彼此共享数据,但与多态类有关系时,此功能很有用。

As an example, let’s think of a social media site like Facebook. On Facebook, both individuals and groups can share posts.

例如,让我们考虑一下Facebook之类的社交媒体网站。 在Facebook上,个人和团体都可以共享帖子。

The individuals and groups are not related (other than both being a type of user), and so they have different data. A group probably has fields like member_count and group_type that don’t apply to an individual, and vice-versa).

个人和组没有关联(除了都是用户类型以外),因此它们具有不同的数据。 群组可能具有诸如member_countgroup_type类的字段,不适用于个人,反之亦然。

Without polymorphic associations, we would have something like this:

没有多态关联,我们将有这样的事情:

class Post  belongs_to :person  belongs to :groupend
class Person  has_many :postsend
class Group  has_many :postsend

Normally, to find out who owns a certain profile, we look at the column that is the foreign_key. A foreign_key is an id used to find the related object in the related model’s table.

通常,要找出谁拥有某个配置文件,我们查看一下foreign_key列。 foreign_key是用于在相关模型的表中查找相关对象的ID。

However, our Posts table would have two competing foreign keys: group_id and person_id. This would be problematic.

但是,我们的Posts表将具有两个相互竞争的外键: group_idperson_id 。 这将是有问题的。

When trying to find the owner of a post, we would have to make a point to check both columns to find the correct foreign_key, rather than relying on one. What happens if we run into a situation where both columns have a value?

在尝试查找帖子的所有者时,我们必须指出一个要点,即同时检查两列以找到正确的foreign_key,而不要依赖一个。 如果我们遇到两个列都有值的情况,会发生什么?

A polymorphic association addresses this issue by condensing this functionality into one association. We can represent our classes like this:

多态关联通过将此功能浓缩为一个关联来解决此问题。 我们可以这样表示我们的类:

class Post  belongs_to :postable, polymorphic: trueend
class Person  has_many :posts, as :postableend
class Group  has_many :posts, as :postableend

The Rails convention for naming a polymorphic association uses “-able” with the class name (:postable for the Post class). This makes it clear in your relationships which class is polymorphic. But you can use whatever name for your polymorphic association that you like.

用于命名多态关联的Rails约定使用带有类名的“ -able”(对于Post类,为:postable )。 这样可以在您的关系中明确指出哪个类是多态的。 但是,您可以为自己的多态关联使用任何名称。

To tell our database we’re using a polymorphic association, we use special “type” and “id” columns for the polymorphic class.

为了告诉数据库我们正在使用多态关联,我们对多态类使用特殊的“类型”和“ id”列。

The postable_type column records which model the post belongs to, while the postable_id column tracks the id of the owning object:

postable_type列记录帖子所属的模型,而postable_id列跟踪拥有对象的ID:

haley = Person.first=> returns Person object with name: "Haley"
article = haley.posts.firstarticle.postable_type=> "Person"
article.postable_id=> 1 # The object that owns this has an id of 1 (in this case a      Person)
new_post = haley.posts.new()# Automatically fills in postable_type and postable_id using haley object

A polymorphic association is just a combination of two or more belongs_to associations. Because of this, you can act the same way you would when using two models that have a belongs_to association.

多态关联只是两个或多个belongs_to关联的组合。 因此,您可以使用与使用两个具有belongs_to关联的模型相同的方式进行操作。

Note: polymorphic associations work with both has_one and has_many associations.

注意:多态关联与has_one和has_many关联一起使用。

haley.posts# returns ActiveRecord array of posts
haley.posts.first.content=> "The content from my first post was a string..."

One difference is going “backwards” from a post to access its owner, since its owner could come from one of several classes.

一种区别是从帖子“向后”访问其所有者,因为其所有者可能来自多个类别之一。

To do that quickly, you need to add a foreign key column and a type column to the polymorphic class. You can find the owner of a post using postable:

要快速做到这一点,您需要向多态类添加外键列和类型列 。 您可以使用postable查找帖子的所有者:

new_post.postable=> returns Person object
new_post.postable.name=> "Haley"

Additionally, Rails implements some security within polymorphic relationships. Only classes that are part of the relationship can be included as a postable_type:

另外,Rails在多态关系中实现了一些安全性。 只有属于关系的类才可以作为postable_type包括在内:

new_post.update(postable_type: "FakeClass")=> NameError: uninitialized constant FakeClass

警告 (Warning)

Polymorphic associations come with one huge red flag: compromised data integrity.

多态关联带有一个巨大的危险信号: 数据完整性受损

In a normal belongs_to relationship, we use foreign keys for reference in an association.

在正常的belongs_to关系中,我们使用外键在关联中进行引用。

They have more power than just forming a link, though. Foreign keys also prevent referential errors by requiring that the object referenced in the foreign table does, in fact, exist.

但是,它们不仅仅具有链接的功能。 外键还通过要求确实存在外表中引用的对象来防止引用错误。

If someone tries to create an object with a foreign key that references a null object, they will get an error.

如果有人尝试使用引用空对象的外键创建对象,则会收到错误消息。

Unfortunately, polymorphic classes can’t have foreign keys for the reasons we discussed. We use the type and id columns in place of a foreign key. This means we lose the protection that foreign keys offer.

不幸的是, 由于我们讨论的原因 ,多态类不能具有外键。 我们使用typeid列代替外键。 这意味着我们将失去外键提供的保护。

Rails and ActiveRecord help us out on the surface, but anyone with direct access to the database can create or update objects that reference null objects.

Rails和ActiveRecord可以帮助我们从表面上解决问题,但是直接访问数据库的任何人都可以创建或更新引用空对象的对象。

For example, check out this SQL command where a post is created even though the group it is associated with doesn’t exist.

例如,即使该帖子所关联的组不存在,也请签出此SQL命令在何处创建帖子。

Group.find(1000)=> ActiveRecord::RecordNotFound: Couldn't find Group with 'id'=1000
# SQLINSERT INTO POSTS (postable_type, postable_id) VALUES ('Group', 1000)=> # returns success even though the associated Group doesn't exist

Thankfully, proper application setup can prevent this from being possible. Because this is a serious issue, you should only use polymorphic associations when your database is contained. If other applications or databases need to access it, you should consider other methods.

幸运的是,正确的应用程序设置可以防止这种情况的发生。 因为这是一个严重的问题,所以仅在包含数据库时才应使用多态关联。 如果其他应用程序或数据库需要访问它,则应考虑其他方法。

Polymorphic association PROS:

多态关联PROS:

  • Easy to scale in amount of data: information is distributed across several database tables to minimize table bloat易于扩展数据量:信息分布在多个数据库表中,以最大程度地减少表膨胀
  • Easy to scale number of models: more models can be easily associated with the polymorphic class易于缩放的模型数量:可以轻松地将更多模型与多态类关联
  • DRY: creates one class that can be used by many other classesDRY:创建一个可以被许多其他类使用的类

Polymorphic association CONS

多态关联CONS

  • More tables can make querying more difficult and expensive as the data grows. (Finding all posts that were created in a certain time frame would need to scan all associated tables)随着数据的增长,更多的表会使查询变得更加困难和昂贵。 (查找在特定时间范围内创建的所有帖子都需要扫描所有关联的表)
  • Cannot have foreign key. The id column can reference any of the associated model tables, which can slow down querying. It must work in conjunction with the type column.

    不能有外键。 id列可以引用任何关联的模型表,这可能会降低查询速度。 它必须与type列一起使用。

  • If your tables are very large, a lot of space is used to store the string values for postable_type

    如果表非常大,则会使用大量空间来存储postable_type的字符串值

  • Your data integrity is compromised.您的数据完整性受到损害。

如何知道使用哪种方法 (How to know which method to use)

STI and polymorphic associations have some overlap when it comes to use cases. While not the only solutions to a “tree-like” model relationship, they both have some obvious advantages.

在用例方面,STI和多态关联有一些重叠。 虽然不是“树状”模型关系的唯一解决方案,但它们都有明显的优势。

Both the Vehicle and Postable examples could have been implemented using either method. However, there were a few reasons that made it clear which method was best in each situation.

VehiclePostable示例都可以使用这两种方法来实现。 但是,出于多种原因可以弄清楚哪种方法在每种情况下都是最佳的。

Here are four factors to consider when deciding whether either of these methods fits your needs.

在确定这两种方法是否适合您的需求时,需要考虑以下四个因素。

  1. Database structure. STI uses only one table for all classes in the relationship, while polymorphic associations use a table per class. Each method has its own advantages and disadvantages as the application grows.

    数据库结构。 STI对关系中的所有类仅使用一个表,而多态关联对每个类使用一个表。 随着应用程序的增长,每种方法都有其自身的优缺点。

  2. Shared data or state. STI is a great option if your models have many shared attributes. Otherwise a polymorphic association is probably the better choice.

    共享的数据或状态。 如果您的模型具有许多共享属性,则STI是一个不错的选择。 否则,多态关联可能是更好的选择。

  3. Future concerns. Consider how your application might change and grow. If you’re considering STI but think you’ll add models or model fields that deviate from the shared structure, you might want to rethink your plan. If you think your structure is likely to remain the same, STI will generally be faster for querying.

    未来的担忧。 考虑您的应用程序可能如何更改和增长。 如果您正在考虑STI,但认为您将添加偏离共享结构的模型或模型字段,则可能需要重新考虑您的计划。 如果您认为您的结构可能保持不变,则STI 通常可以更快地进行查询。

  4. Data integrity. If data is not going to be contained (one application using your database), polymorphic association is probably a bad choice because your data will be compromised.

    数据的完整性。 如果不包含数据(使用数据库的一个应用程序),则多态关联可能是一个不好的选择,因为数据将受到损害。

最后的想法 (Final Thoughts)

Neither STI nor polymorphic associations are perfect. They both have pros and cons that often make one or the other more fit for associations with many models.

STI和多态关联都不是完美的。 它们都有优点和缺点,通常使一个或多个更适合与许多模型关联。

I wrote this article to teach myself these concepts just as much as to teach them to anyone else. If there is anything incorrect or any points you think should be mentioned, please help me and everyone else out by sharing in the comments!

我写这篇文章是为了向自己教授这些概念,就像向其他任何人教它们一样。 如果有任何不正确的地方或您认为应该提及的任何观点,请分享评论,以帮助我和其他所有人!

If you learned something or found this helpful, please click on the ? button to show your support!

如果您学到了什么或发现有帮助,请单击“ ?”。 按钮表示您的支持!

翻译自: https://www.freecodecamp.org/news/single-table-inheritance-vs-polymorphic-associations-in-rails-af3a07a204f2/

rails 两表关联查询

rails 两表关联查询_Rails中的单表继承与多态关联:找到适合您的方法相关推荐

  1. mysql同张表关联多次查询_MySQL多次单表查询和多表联合查询

    Tip:不建议执行三张表以上的多表联合查询 对数据量不大的应用来说,多表联合查询开发高效,但是多表联合查询在表数据量大,并且没有索引的时候,如果进行笛卡儿积,那数据量会非常大,sql执行效率会非常低 ...

  2. 一条SQL语句查询数据库中的所有表、存储过程、触发器

    一条SQL语句查询数据库中的所有表.存储过程.触发器 (sysobjects表信息)   该条语句查询返回所有的用户表 select * from sysobjects where xtype='u' ...

  3. Oracle查询数据库中所有的表名称

    1.查询数据库中所有的表名称和每张表所对应的数据条数 select t.table_name,t.num_rows from user_tables t; 此处需要注意的是:在查询每张表所对应的数据条 ...

  4. 查询库中所有的表名及数据量

    sql代码直接执行即可 sqlserver查询库中所有的表名及数据量 SELECTa.name,b.rows FROMsysobjects AS aINNER JOIN sysindexes AS b ...

  5. oracle表连接查询逗号隔开_Oracle多表连接查询

    连接:将一张表中的行按照某种条件和另一张表中的行连接起来形成一个新行的的过程. 根据连接查询返回的结果,分为3类: 内连接(inner join) 外连接(outer join) 交叉连接(cross ...

  6. mysql查询结果更新到新表_MySQL查询结果复制到新表的方法(更新、插入)

    MySQL中可以将查询结果复制到另外的一张表中,复制的话通常有两种情况,一种是更新已有的数据,另一种是插入一条新记录.下面通过例子来说明.首先构建两个测试表. 表t1: 表t2: 1.如果t2表中存在 ...

  7. mysql 一对多 右表多条记录合并_MYSQL 单表一对多查询,将多条记录合并成一条记录...

    一.描述: 在MySQL 5.6环境下,应工作需求:将一个表中多条某个相同字段的其他字段合并(不太会表达,有点绕,直接上图) 想要达到的效果: 实现SQL语句: SELECT a.books, GRO ...

  8. iBatis 事务控制 与 两表操作将SQL语句写入单表

    事务控制 示例: // move data from temp_table to work_tabletry {sqlMapClient.startTransaction();T03SlipWk or ...

  9. mysql 评价表设计_来聊聊mysql单表评论系统怎么设计

    评论系统对于一个网站来说几乎是必不可少的,当然评论系统的设计也多种多样.一般情况下,评论数据表会和一个用户信息表结合使用,就是在评论表中记录的有用户id(例如user_id),然后查询评论数据的时候根 ...

最新文章

  1. 最新android webview,Android 关于WebView全方面的使用(项目应用篇)
  2. 如何用tadodataset.append
  3. 人生财富值得珍藏的文字
  4. linux网卡设置详解,史上最详细的Linux网卡ifcfg-eth0配置详解
  5. python亲和性分析法推荐电影论文_关于《Python数据挖掘入门与实战》读书笔记二(亲和性分析)...
  6. 这些让人看瞎了的设计!实力证明,谁才是世界的最终boss!
  7. 计算机组成西电裘答案,西电计算机组成原理.ppt
  8. Java一对多关系示例
  9. Window10 NVIDIA显卡 Tensorflow 2.1 GPU 安装和测试
  10. 三网物联卡的优缺点有哪些
  11. JSP中的坑(二):使用include包含jsp文件时contentType中charset的值区分大小写
  12. 百度 tts 语音合成前端无法播放问题解决
  13. 上传图片到腾讯云(海外服务器)com.qcloud5.5.4版本
  14. python中close函数的用法_skft包 pythonpython close()是什么?python close()定义及用法详解...
  15. 已成功拿下字节、腾讯、脉脉offer,这原因我服了
  16. Java DAO是啥?
  17. 【市场点评】沪深基指终强势反弹 终结六连阴走势
  18. PHP使用QQ邮箱发送邮件
  19. 一文了解2万美金的CQF量化金融分析师证书
  20. 【What if 系列】风挡与雨滴

热门文章

  1. 窗体控件绑定泛型数组 0104 c#
  2. 06 使用VS2012开发简单控制器程序 1214
  3. 爬虫-代理的爬取练习191110
  4. [转]DPM2012系列之十八:如何保护工作组计算机
  5. ContOS网络连接及简单的ssh Xshell连接!
  6. SOFA 源码分析 — 扩展机制
  7. C语言版数据结构及算法_快速排序
  8. Tensorflow 相关概念
  9. openlayers 3读取加载geojson格式数据
  10. NFS与NAS谁更适合VMware