我知道当您使用.references
并在联接表上指定# will error out or throw deprecation warning in logs
customers = Customer.includes(:orders).where("Orders.cost < ?", 100)
子句时,您应该使用customers
示例:
customers
否则,在rails 4或更高版本中,您将收到如下错误:
Mysql2 ::错误:未知列&#39; Orders.cost&#39;在&#39; where子句&#39;:SELECT
Post.includes(:comments).where("comments.title = 'foo'")
。* FROMconfig.active_record.disable_implicit_join_references = true
WHERE(Orders.cost&lt; 100)
或者您会收到弃用警告:
弃权警告:您似乎渴望装载桌子 (字符串SQL中引用的一个:用户,地址) 片段。例如:
includes
目前,Active Record识别字符串中的表,并且知道 将评论表加入查询,而不是加载评论 在单独的查询中。然而,这样做没有写完全 SQL解析器本质上是有缺陷的。因为我们不想写SQL 解析器,我们正在删除此功能。从现在开始,你必须明确 当您从字符串引用表时,告诉Active Record:
Post.includes(:comments).where(&#34; comments.title =&#39; foo&#39;&#34;)。references(:comments)
如果您不依赖隐式联接引用,则可以禁用 功能完全通过设置
# No error and no deprecation warning because we are explicitly specifying what table is referenced within that where clause customers = Customer.includes(:orders).where("Orders.cost < ?", 100).references(:orders)
。 (SELECT&#34;用户&#34;。&#34; id&#34; AS t0_r0,&#34;用户&#34;。&#34;名称&#34; AS t0_r1,&#34;用户&#34;。&#34;电子邮件&#34; AS t0_r2,&#34;用户&#34;。&#34; created_at&#34; AS t0_r3, #&34;用户&#34;&#34;的updated_at&#34; AS t0_r4, &#34;地址&#34;&#34; ID&#34; AS t1_r0,&#34;地址&#34;。&#34; user_id&#34; AS t1_r1,&#34;地址&#34;。&#34; country&#34; AS t1_r2,&#34;地址&#34;。&#34; street&#34; AS t1_r3, &#34;地址&#34;&#34; POSTAL_CODE&#34; AS t1_r4,&#34;地址&#34;。&#34;城市&#34; AS t1_r5, &#34;地址&#34;&#34; created_at&#34; AS t1_r6,&#34;地址&#34;。&#34; updated_at&#34; AS t1_r7 来自&#34;用户&#34; LEFT OUTER JOIN&#34;地址&#34; ON&#34;地址&#34;。&#34; user_id&#34; =&#34;用户&#34;。&#34; id&#34; WHERE(addresses.country =&#39;波兰&#39;)
有道理。使用joins
时,Rails不希望成为SQL解析器。因此,为了让铁路开心,我们这样做:
where
但是,当您在连接表上使用includes
和# No error and no deprecation warning. What????
customers = Customer.joins(:orders).where("Orders.cost < ?", 100)
子句时:Rails不会出错,并且rails也不会像includes
那样抛出弃用警告:
joins
这对我没有意义。我认为如果rails不想成为references
的SQL解析器,那么它也不希望成为customers = Customer.joins(:orders).where("Orders.cost < ?", 100).references(:orders)
的SQL解析器。我认为rails会更喜欢我这样使用references
:
joins
所以我的问题:
where
指定includes
并在连接表上使用includes
子句,即使joins
几乎需要它?如果是这样:为什么references
和joins
之间存在差异?joins
前进中指定where
吗?也许一旦铁路&#39; sql解析器消失所有那些{{1}}的{{1}}子句在连接的表上将不再有效?答案 0 :(得分:6)
joins
和includes
(两种方法的包装:eager_load
和preload
)之间的根本区别在于:
joins
直截了当地执行SQL并不加选择地返回所有记录includes
将确定哪些记录属于哪个模型并构建模型树:author1 -> [post, post, post], author2 -> [post, post]
例如,如果您加入Order.joins(:product_items)
,您将获得:
Order.includes(:product_items)
只有 ,Orders
的每个相应订单中都嵌套了product_items。所以这里的reference
只有在includes
(或eager_load
或preload
)帮助区分SQL连接数据时才对Rails有用。将其分配给适当的模型。
使用joins
,您可以在SQL世界中独立完成。大多数情况下,我会将其与group("orders.id")
和聚合函数一起使用:
select(orders.*, count(product_items.id) as cart_size)
...
答案 1 :(得分:1)
这里的关键区别是includes
有两种操作模式:eager_load(每个关联使用一个连接)和preload(为每个关联运行一个单独的查询,因此不支持引用的条件)联合表)
在rails 2(或其附近)之前,唯一的选择是基于连接的选项。当新策略被引入时,它被设为默认策略,如果为了减少人们应用中的回归而看起来需要回退旧策略。
这种检测总是有点混乱,并且有一个永无止境的长尾病例没有检测到,因此最终决定删除回退并要求明确使用references
来指示哪些包含的关联在查询的任何子句中使用。您可以在eager_loading?方法中看到这一点,该方法用于决定使用哪种策略。
您还可以使用preload
或eager_load
代替includes
来直接指出您想要的策略(或针对不同的关联使用不同的策略)。
另一方面,joins
始终进行连接 - 它从不需要解析您的查询,因为它根本不需要 - 无论如何都会生成连接子句。