【问题标题】:Eager load associations when querying against association data查询关联数据时急切加载关联
【发布时间】:2019-04-16 07:42:43
【问题描述】:

我有一个模型“用户”,它与另一个模型“会员”有一对多的关系。成员资格有一个名为“组”的字段,该字段具有组的名称。我想查询特定“组”中的所有用户记录,并为返回的每个用户急切加载所有“成员资格”。

在进一步讨论之前,我知道通常您会实现一个“组”模型,并使成员资格成为用户和组之间的连接表,然后只查询特定组的所有用户。这个例子有点做作,但它代表了我正在研究的真实案例。

无论如何,我尝试了以下查询:

User.includes(:memberships).where(memberships: { group: groupname })

但是,虽然这会返回正确的用户,但它只会急切加载与查询匹配的成员资格。换句话说,如果用户“Bob”在“red”和“blue”组中,我查询所有“blue”组用户,结果中返回用户“Bob”,但只返回他的“blue”组成员身份已加载。

有没有办法通过单个数据库查询并立即加载每个返回用户的所有成员资格?

【问题讨论】:

    标签: ruby-on-rails activerecord rails-activerecord


    【解决方案1】:

    在您的示例中,由于关联存在查询条件,因此执行了单个数据库查询。通常,includes 会执行两个数据库查询,一个用于加载用户,另一个用于加载关联的成员资格。

    我注意到了这一点,因为有一个解决方案可以执行两个数据库查询,而且很好(默认 ActiveRecord 急切加载行为)

    User.preload(:memberships).joins(:memberships).where(memberships: {group: groupname})
    

    注意:在示例中使用preload 方法而不是includes。这是为了仅在第一个查询中应用关联表上的查询条件,并且不影响预加载 memberships 的第二个查询。默认情况下,当关联表上没有额外的查询条件时,include 的作用类似于preload

    第一个查询将获取所有具有所需组成员身份的用户。

    第二个查询将在没有任何额外条件的情况下获取所有关联的成员资格。

    【讨论】:

    • 这看起来不错。是的,我确实说过“单个数据库查询”,但我真正的意思是“不考虑用户数量的固定查询集”,所以这很好用。只是为了确保我理解这里发生的事情,“joins”执行内部连接,因此“where”子句可以根据组名对用户进行匹配,但实际上并不加载任何成员资格数据。 “preload”调用实际上将成员数据加载到内存中,但是因为它是在单独的查询中执行的,所以它不受“where”子句的影响。听起来对吗?
    • 没错。我还想澄清一件事:“preload”调用不受“where”子句的影响,不仅因为它是一个单独的查询,还因为 Rails 没有将“where”子句添加到查询中。如果您使用include 而不是preload,您将在两个查询中使用相同的“where”子句。事实上,我不能说这是预期的行为,它就是它的工作方式。
    • 谢谢。我一直想知道为什么有人会使用预加载而不是包含。现在我知道了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 2018-07-28
    相关资源
    最近更新 更多