ruby-on-rails - ActiveRecord 嵌套关联
问题描述
我有一些模型,Service
例如Payment
Manager
class Service < ApplicationRecord
validates :name, presence: true
has_and_belongs_to_many :tickets
has_many :payments
end
class Payment < ApplicationRecord
belongs_to :manager
belongs_to :service
validates :value, :manager_id, :service_id, presence: true
end
class Manager < ApplicationRecord
validates :name, presence: true
end
Service
可以有多个Payment
s 并且每个Payment
都有一个Manager
.
我想使用所有嵌套关联作为哈希来获取整个数据,我可以重新格式化(或映射)并发送给客户端。我被查询困住了:
Service.includes(payments: :manager).references(:payments, :managers)
因为它正在使用延迟加载,所以我需要执行以下操作:
services.first.payments.first.manager
获取数据,这是非最优的。
是否可以使用所有嵌套关联获取所有数据?
我做了这样的计算:
services = Service.includes(payments: :manager)
.references(:payments, :managers)
result = []
services.each do |service|
service.payments.each do |payment|
manager_name = payment[:manager][:name]
value = payment[:value]
service[manager_name] = value
end
result.push(service)
end
NoMethodError (undefined method '[]' for nil:NilClass):
并在线出错manager_name = payment[:manager][:name]
。
解决方案
经过多次尝试,我终于找到了一些我制作的拼写错误并归档了我想要使用此类代码的行为
services = Service.eager_load(payments: :manager)
services.reduce([]) do |acc, service|
service_rec = {
id: service[:id],
name: service[:name],
surgery: service[:surgery]
}
service.payments.each do |payment|
manager_name = payment.manager[:name]
value = payment[:value]
service_rec[manager_name] = value
end
acc.push(service_rec)
end
和它产生的 SQL 查询
SQL (0.2ms) SELECT "services"."id" AS t0_r0, "services"."code" AS t0_r1, "services"."name" AS t0_r2, "services"."surgery" AS t0_r3, "services"."enabled" AS t0_r4, "services"."created_at" AS t0_r5, "services"."updated_at" AS t0_r6, "payments"."id" AS t1_r0, "payments"."service_id" AS t1_r1, "payments"."manager_id" AS t1_r2, "payments"."value" AS t1_r3, "payments"."created_at" AS t1_r4, "payments"."updated_at" AS t1_r5, "managers"."id" AS t2_r0, "managers"."name" AS t2_r1, "managers"."enabled" AS t2_r2, "managers"."created_at" AS t2_r3, "managers"."updated_at" AS t2_r4 FROM "services" LEFT OUTER JOIN "payments" ON "payments"."service_id" = "services"."id" LEFT OUTER JOIN "managers" ON "managers"."id" = "payments"."manager_id"
有趣的是,使用includes
而不是eager_load
产生三个查询
Service Load (0.1ms) SELECT "services".* FROM "services"
↳ app/services/payments_service.rb:6
Payment Load (0.1ms) SELECT "payments".* FROM "payments" WHERE "payments"."service_id" IN (?, ?, ?, ?, ?, ?, ?, ?) [["service_id", 1], ["service_id", 2], ["service_id", 3], ["service_id", 4], ["service_id", 5], ["service_id", 6], ["service_id", 7], ["service_id", 8]]
↳ app/services/payments_service.rb:6
Manager Load (0.1ms) SELECT "managers".* FROM "managers" WHERE "managers"."id" IN (?, ?, ?, ?) [["id", 1], ["id", 2], ["id", 3], ["id", 4]]
我们也可以使用Service.includes(payments: :manager).references(:payments, :managers)
并获得相同的查询,eager_load
但输入时间更长))
感谢大家的参与!有人对eager_load
代码优化建议有其他意见吗?
推荐阅读
- quickfixj - 如何使用 QuickFIX/J 加载资源中的数据字典
- java - 使用 Spring Data JPA 处理 POST 请求中的关系
- node.js - 如何在 Node.js 中停止异步线程
- php - 来自多维数组的 flatten_array 函数 - 未定义
- postgresql - ElasticSearch - 如何在哈希中查询两个时期之间的数据
- php - PHP/IIS - Sessions_save_path - 会话数据已创建但发生错误且无法完成安装
- java - 以文本格式存储由 KeyStoreGenerator 生成的私钥(例如保管库存储) - Java
- reactjs - 失败的道具类型:道具`id`在`FormattedMessage`中标记为必填,但其值为`undefined`
- c# - 从另一台 PC 访问 Webservice API
- python - 使用 elementtree Python 从 XML 中删除元素和子项