Rails中不使用原生SQL按关联表字段调用group()方法的问题
ActiveRecord关联表分组查询merge方法不生效解决方案
问题表现
执行关联表分组查询时,希望不编写原生SQL字符串,按已join的关联表字段分组。
硬编码表名的写法可以正常运行:
Sale::Product.joins(stock_product: :supplier).group('core_suppliers.id').first
生成SQL符合预期:
SELECT `sale_products`.* FROM `sale_products` INNER JOIN `stock_products` ON `stock_products`.`deleted_at` IS NULL AND `stock_products`.`id` = `sale_products`.`stock_product_id` INNER JOIN `core_suppliers` ON `core_suppliers`.`id` = `stock_products`.`core_supplier_id` GROUP BY core_suppliers.id ORDER BY `sale_products`.`id` ASC LIMIT 1
尝试用merge方法复用关联模型的group条件,避免硬编码表名:
Sale::Product.joins(stock_product: :supplier).merge(::Core::Supplier.group(:id)).first
生成的SQL分组字段错误,被错误归属到主表:
SELECT `sale_products`.* FROM `sale_products` INNER JOIN `stock_products` ON `stock_products`.`deleted_at` IS NULL AND `stock_products`.`id` = `sale_products`.`stock_product_id` INNER JOIN `core_suppliers` ON `core_suppliers`.`id` = `stock_products`.`core_supplier_id` GROUP BY `sale_products`.`core_supplier_id` ORDER BY `sale_products`.`id` ASC LIMIT 1
相同写法合并order条件时可正常生效,仅group条件出现解析异常。
根本原因
Rails对merge方法中不同查询条件的解析逻辑不一致:
- 合并
order条件时,会保留条件原始所属模型的表名前缀,能正确映射到关联表字段 - 合并
group条件时,Rails 6.1及更早版本会默认将传入字段归属到当前查询的主模型对应表,不会自动识别关联模型的上下文,因此出现字段表名解析错误。
无原生SQL的实现方案
不需要硬编码表名,以下两种写法都可以正确生成关联表分组的SQL:
- 使用Arel表指定字段,完全规避硬编码:
Sale::Product.joins(stock_product: :supplier).group(Core::Supplier.arel_table[:id]).first
- Rails 6.0及以上版本支持嵌套关联哈希传参,自动解析对应表名:
Sale::Product.joins(stock_product: :supplier).group(stock_product: { supplier: :id }).first
两种写法最终生成的SQL都会正确指向core_suppliers.id字段,不存在硬编码表名带来的维护问题。
内容的提问来源于stack exchange,提问作者Theoran
相关产品推荐
相关产品推荐

