匹配嵌套模型关联属性与包括 [英] Matching nested model association attribute with includes

查看:215
本文介绍了匹配嵌套模型关联属性与包括的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下型号:

class Post < ActiveRecord::Base
  has_many :authors

class Author < ActiveRecord::Base
  belongs_to :post

和假设作者模型有一个属性,名称

And suppose the Author model has an attribute, name.

我要寻找一个给定的作者爱丽丝的所有职位,由该作者姓名。说有另一位作者鲍勃谁共同撰写与Alice后。

I want to search for all posts with a given author "alice", by that author's name. Say there is another author "bob" who co-authored a post with alice.

如果我搜索使用的第一个结果包括其中,

If I search for the first result using includes and where:

post = Post.includes(:authors).where("authors.name" => "alice").first

您会看到该职位只有一个作家,现在,即使在实际上有更多的:

You'll see that the post only has one author now, even if in fact there are more:

post.authors #=> [#<Author id: 1, name: "alice", ...>]
post.reload
post.authors #=> [#<Author id: 1, name: "alice", ...>, #<Author id: 2, name: "bob", ...>]

这个问题似乎是组合包括其中,,它正确地限制了范围,所需职位的,但在同一时间隐藏了所有关联除了为匹配所述一个

The problem seems to be the combination of includes and where, which limits the scope correctly to the desired post, but at the same time hides all associations except for the one that is matched.

我想结束了一个的ActiveRecord ::关联的链接,所以上面的重装解决方案是不是真的满意。更换包括加入解决了这个,但不急于负荷的关联:

I want to end up with an ActiveRecord::Relation for chaining, so the reload solution above is not really satisfactory. Replacing includes by joins solves this, but does not eager load the associations:

Post.joins(:authors).where("authors.name" => "alice").first.authors
#=> [#<Author id: 1, name: "alice", ...>, #<Author id: 2, name: "bob", ...>]
Post.joins(:authors).where("authors.name" => "alice").first.authors.loaded?
#=> false

有什么建议?在此先感谢,我一直在敲打我的头在这个问题了一会儿。

Any suggestions? Thanks in advance, I've been banging my head over this problem for a while.

推荐答案

我看到你在做什么是预期的行为,至少是如何SQL工作......你限制在作者的加入到authors.id = 1,那么,为什么它加载任何其他人? ActiveRecord的只是需要数据库返回的行,它没有办法知道是否有其他人,而不做其他查询基础上,posts.id的。

I see what you're doing as expected behaviour, at least that's how SQL works... You're restricting the join on authors to where authors.id = 1, so why would it load any others? ActiveRecord just takes the rows that the database returned, it has no way of knowing if there are others, without doing another query based on the posts.id.

下面是使用子查询一个可能的解决方案,这将作为一个可链接的关系,并执行一个查询:

Here's one possible solution with a subquery, this will work as a chainable relation, and executes in one query:

relation = Post.find_by_id(id: Author.where(id:1).select(:post_id))

如果您添加包括,你会看到查询发生以下两种方法之一:

If you add the includes, you will see the queries happen one of two ways:

relation = relation.includes(:authors)

relation.first
# 1. Post Load SELECT DISTINCT `posts`.`id`...
# 2. SQL SELECT `posts`.`id` AS t0_r0, `posts`.`title` AS t0_r1, ...

relation.all.first
# 1. SQL SELECT `posts`.`id` AS t0_r0, `posts`.`title` AS t0_r1, ...

因此​​根据方案,ActiveRecord的判定是否查找的ID利用更简单的查询装载所有相关的作者之前。有时,它更有意义,运行2步查询。

So depending on the scenario, ActiveRecord decides whether to look up the id with a simpler query before loading all the associated authors. Sometimes it makes more sense to run the query in 2 steps.

这篇关于匹配嵌套模型关联属性与包括的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆