【问题标题】:how to check if has_one exists without loading associated model如何在不加载关联模型的情况下检查 has_one 是否存在
【发布时间】:2020-09-06 15:43:55
【问题描述】:

我有一个简单的 has_one 关系

class User < ApplicationRecord
  has_one :detail
  has_many :courses
end

class Detail < ApplicationRecord
  belongs_to :user
end

我需要检查用户是否有详细信息。因为我可以做到User.first.courses.exists?,所以User.first.detail.exists? 不起作用令人惊讶。我可以做!User.first.detail.nil?,但我只需要检查用户详细信息是否存在而不加载它非常庞大的详细信息模型。

在不检索整个关联模型的情况下检查 has_one 关联是否存在的好方法是什么?

【问题讨论】:

    标签: ruby-on-rails activerecord ruby-on-rails-6


    【解决方案1】:

    要检查关联是否已加载而不点击数据库,您可以使用:

    model.association(:association_name).loaded? 用于has_one/belongs_to 关联,model.many_things.loaded? 用于has_many 关联。

    检查 has_one/belongs_to 关联是否已加载:

    user = User.find(1)
    
    user.association(:detail).loaded? # => false
    
    user.detail.id # Does DB request to get Detail
    
    user.association(:detail).loaded? # => true
    
    预加载

    Eager loading 让您可以提前加载数据,因此正如预期的那样,关联被标记为已加载:

    user = User.eager_load(:detail).find(1)
    user.detail.loaded? # => true
    

    检查 has_many 关联是否已加载

    使用 has_many 关联,

    user = User.find(1)
    user.association(:courses).loaded? # => false
    
    user.courses.load # Does DB query to get all users' courses
    user.association(:courses).loaded? # => true
    
    执行.first 或其他一些查询不会总是加载

    请记住,它并非在所有情况下都标记为已加载:

    user.courses.first.id # Does DB query to get first course ID
    user.association(:courses).loaded? # => false (still!)
    

    这是因为它实际上是在执行 SELECT * LIMIT 1 查询时,您为了提高效率而执行 .first

    预加载
    user = User.eager_load(:courses).find(1)
    user.association(:courses).loaded? # => true
    

    何时使用loaded? 方法?

    我能想到的唯一用例是当您不想触发数据库调用但您想检查数据是否已经加载并仅在加载时才对其进行处理。

    在我的例子中,我想输出一些数据用于记录目的,但前提是它没有通过调用关联添加额外的数据库查询。

    【讨论】:

      【解决方案2】:

      您可以使用:User.first.detail.present?

      【讨论】:

      • OP 要求不加载 detail 模型。这个答案将查询和分配 User 和 Detail 模型。
      • @James 是正确的,因为它仍然执行数据库查询。我在上面发布了我认为是 OP 想要的答案:stackoverflow.com/a/69349863/1454001
      【解决方案3】:

      Detail.exists?(User.first.detail_id)

      如果详细信息被删除,即使detail_id 为零,这也会起作用。并且这不会导致查询明细列和分配明细对象。

      【讨论】:

      • 这不起作用,因为detailhas_one 关联,所以用户上没有detail_id
      猜你喜欢
      • 2011-01-04
      • 2022-12-10
      • 1970-01-01
      • 2012-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-15
      • 2013-04-12
      相关资源
      最近更新 更多