我有以下示例查询:
source = "(SELECT DISTINCT source.* FROM (SELECT * FROM items) AS source) AS items"
items = Item.select("items.*").from(source).includes([:images])
p items # [#<Item id: 1>, #<Item id:2>]
但是正在运行:
p items.count
Arel::Nodes:SqlLiteral`的NoMethodError: undefined method
映射中的结果
我很欣赏这个查询很傻,但是非simplefieid查询有点太复杂了,无法复制,这是我能创建的最小崩溃版本。有什么想法吗?
您能在该对象上调用all
以将其强制转换为Array吗?
Item.select("items.*").from(source).includes([:images]).all.count
或者在这种情况下,size
可能更合适。在任何情况下,这都将执行查询并将所有对象加载到内存中,这可能是不可取的。
看起来问题出在你的includes([:images])
上。在类似的应用程序上,我可以从控制台执行:
> Category.select('categories.*').from('(SELECT DISTINCT source.* FROM (SELECT * FROM categories) AS source) AS categories').count
(0.5ms) SELECT COUNT(*) FROM (SELECT DISTINCT source.* FROM (SELECT * FROM categories) AS source) AS categories
(请注意,count
覆盖SELECT子句,尽管我明确指定了items.*
。但它们仍然是等效的查询。)
一旦我添加includes
作用域,它就会失败:
> Category.select('categories.*').from('(SELECT DISTINCT source.* FROM (SELECT * FROM categories) AS source) AS categories').includes(:projects).count
NoMethodError: undefined method `left' for #<Arel::Nodes::SqlLiteral:0x131d35248>
我尝试了几种不同的方法来获取计数,比如select('COUNT(categories.*)')
,但它们都以各种方式失败了。ActiveRecord似乎依赖于基本的LEFT OUTER JOIN来执行热切加载,可能是因为它认为您正在使用某种条件或外部表来执行联接,这似乎混淆了它执行计数的正常方法。请参阅ActiveRecord::Associations
文档中"热切加载"部分的末尾。
我的建议
如果联接不影响外部查询中返回的行数,我认为最好的办法是执行一个查询来获得计数,执行一个询问来获得实际结果。在我们的分页应用程序中,我们必须执行类似的操作:一个查询返回当前页面的结果,另一个查询则返回与筛选条件匹配的记录总数。
问题是Rails#24193https://github.com/rails/rails/issues/24193并且与CCD_ 10结合急切加载有关。解决方法是使用以下形式:Item.select("items.*").from([Arel.sql(source)]).includes([:images])