简体   繁体   English

当使用has_many:通过rails时,查询可以从所有三个表中产生字段吗?

[英]when use has_many :through in rails, can a query yield fields from all three tables?

In my app, the main objects are Accounts and Phones, with a typical has_many :through Contacts, eg: 在我的应用中,主要对象是“帐户”和“电话”,典型的has_many是:通过“联系人”,例如:

Account:
has_many :contacts
has_many :phones, :though => contacts

Phone:
has_many :contacts
has_many :accounts, :though => :contacts

Contact:
belongs_to :account
belongs_to :phone

Contacts has fields signup_status, name There is one Contact per unique Account/Phone pair 联系人具有signup_status,名称字段,每个唯一的帐户/电话对只有一个联系人

For an account with id = 123, which has 5 contacts, each contact having one phone, is there a query that would yield all 5 rows and include all the account fields AND contact fields AND phone fields? 对于ID = 123的帐户,该帐户有5个联系人,每个联系人都有一个电话,是否存在一个查询,该查询将产生所有5行并包括所有帐户字段,联系人字段和电话字段?

You can use eager loading of associations to get all the data you need in one active record query 您可以使用关联的紧急加载在一个活动记录查询中获取所需的所有数据

@account = Account.includes(:contacts, :phones).find(123)

, which will actually translate into three SQL queries: ,实际上将转换为三个SQL查询:

SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT 1  [["id", 123]]
SELECT "contacts".* FROM "contacts" WHERE "contacts"."account_id" IN (123)
SELECT "phones".* FROM "phones" WHERE "phones"."id" IN (<phone ids found in prev query>)

All of the records will be loaded into memory and become available through @account. 所有记录将被加载到内存中,并通过@account变为可用。 To get the array of contacts and phones, just call @account.contacts and @account.phones , respectively. 要获取联系人和电话列表,只需分别调用@account.contacts@account.phones Note that these calls will not result in re-issued SQL queries, which is the beauty of eager loading. 请注意,这些调用不会导致重新发出SQL查询,这是渴望加载的美妙之处。

ActiveRecord isn't quite smart enough to do all that with one SQL query. ActiveRecord不够智能,无法通过一个SQL查询完成所有这些操作。 You can get pretty close, however, by using includes, which will avoid n+1 queries. 但是,通过使用包含可以使您非常接近,这将避免n + 1个查询。

Account.includes(:contacts => :phones).where(:id => 123)

ActiveRecord will execute one query to load all Account records, one query to load all Contacts, and one query to load all Phones. ActiveRecord将执行一个查询以加载所有帐户记录,执行一个查询以加载所有联系人,并执行一个查询以加载所有电话。 See the link below to the documentation for the reason behind this. 有关此背后的原因,请参见下面的文档链接。

if you really wanted to get everything in one SQL query (which can have drawbacks) you should look at ActiveRecord::Associations::Preloader (documentation) 如果您真的想在一个SQL查询中获得所有内容(这可能会有缺点),则应查看ActiveRecord :: Associations :: Preloader(文档)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM