ruby-on-rails - Rails 关联范围中左连接的子查询

标签 ruby-on-rails ruby-on-rails-4 activerecord orm left-join

我使用 Rails 4.2.0 和 ActiveRecord。我有 Case 模型,其中 has_many :notes

我的主要目标是在一个查询中获取每个案例的最新注释。注释字段应该是可排序的(例如,ORDER BYnotes.created_at)我可以通过这样的 SQL 查询来实现这一点:

SELECT cases.*, notes.* FROM cases
LEFT OUTER JOIN notes ON cases.id = notes.case_id AND notes.id = (
  SELECT id FROM notes 
  WHERE notes.case_id = cases.id 
  ORDER BY notes.created_at DESC 
  LIMIT 1
)
ORDER BY notes.created_at DESC

我当前的case.rb代码如下:

has_one :latest_note, -> do
  where('id' => Note.where('"case_id" = "cases"."id"').order(created_at: :desc).limit(1))
end, inverse_of: :case, class_name: 'Note'

使用eager_load时效果很好:Case.eager_load(:latest_note).order('notes.created_at DESC')

SELECT "cases"."id" AS t0_r0, "cases"."created_at" AS t0_r1, "cases"."updated_at" AS t0_r2, "notes"."id" AS t1_r0, "notes"."case_id" AS t1_r1, "notes"."created_at" AS t1_r2, "notes"."updated_at" AS t1_r3
FROM "cases" LEFT OUTER JOIN "notes" 
  ON "notes"."case_id" = "cases"."id" 
  AND "notes"."id" IN (
    SELECT  "notes"."id" FROM "notes" 
    WHERE ("case_id" = "cases"."id")  
    ORDER BY "notes"."created_at" DESC 
    LIMIT 1
)  ORDER BY notes.created_at DESC

但是会引发错误SQLite3::SQLException:没有这样的列:cases.id而没有eager_load: Case.first.latest_note

SELECT  "notes".* FROM "notes" 
WHERE "notes"."case_id" = ? AND "notes"."id" IN (
  SELECT  "notes"."id" FROM "notes" 
  WHERE ("case_id" = "cases"."id")  
  ORDER BY "notes"."created_at" DESC 
  LIMIT 1
) LIMIT 1

附注有没有没有关联范围的解决方案?通过 joins 进行的原始左连接不适用于 eager_load。如果没有 eager_load,它不会将值从数据库映射到对象 - 日期保留为字符串,而不是 DateTime 对象。

最佳答案

我刚刚找到了解决方法:

来自documentation我发现,该作用域可以接受所有者对象作为参数:

class User < ActiveRecord::Base
  has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
end

所以,我的关系变成了:

has_one :latest_note, ->(kase) do
  subquery = Note.order(created_at: :desc).limit(1)
  subquery = kase.is_a?(Case) ? subquery.where(case_id: kase.id) : subquery.where('"case_id" = "cases"."id"')
  where('id' => subquery)
end, inverse_of: :case, class_name: 'Note'

但是,Rails 4.2.0 输出:

DEPRECATION WARNING: The association scope 'latest_note' is instance dependent (the scope block takes an argument). Preloading happens before the individual instances are created. This means that there is no instance being passed to the association scope. This will most likely result in broken or incorrect behavior. Joining, Preloading and eager loading of these associations is deprecated and will be removed in the future.

此外,此解决方法不适用于预加载(单独的 SQL 查询)

关于ruby-on-rails - Rails 关联范围中左连接的子查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28817477/

相关文章:

ruby-on-rails - Rails MySQL ILIKE 查询

ruby-on-rails - 使用 rake 命名空间作为配置?

ruby-on-rails - 带 sidekiq 的回形针

ruby-on-rails - Rspec 检查返回值

ruby-on-rails - Ruby on Rails 4 身份验证,设计与 bcrypt

ruby-on-rails - 资源中不再存在 Rails 4 图像目录

ruby-on-rails - rails 4——用户预期,得到字符串

ruby-on-rails - 使用自定义 has_many 关系时 nil 的未定义方法名称

ruby-on-rails - 跨子域访问 session (Rails 4)

mysql - 使用现有数据库 ID 的 Ruby on Rails 不起作用