我是否可以使belongs_to关联默认使用预先加载



我正在连接到我公司的一个SQL Server数据库,并尝试设置ActiveRecord,以便我可以将它们视为Rails对象。

我有两个模型:

class Change < ActiveRecord::Base
  belongs_to :affected_contact, class_name: "Contact"
end
class Contact
  # Contact's primary key is a binary UUID; I can't change this
end

我正在尝试获得一个特定更改的受影响联系人。通常,这将是一个简单的情况,但是:

Change.first.affected_contact
  Change Load (52.6ms)  EXEC sp_executesql N'SELECT TOP (1) [chg].* FROM [chg] ORDER BY [chg].[id] ASC'
  Contact Load (28.0ms)  EXEC sp_executesql N'SELECT TOP (1) [ca_contact].* FROM [ca_contact] WHERE [ca_contact].[contact_uuid] = @0', N'@0 binary', @0 = 0xfcf9a8ac6381aa4386c9b10ee382e10b  [["contact_uuid", "<16 bytes of binary data>"]]
=> nil

。那不是我想要的!然而,如果我先急于加载连接,它会起作用:

Change.eager_load(:affected_contact).first.affected_contact
  SQL (34.4ms)  EXEC sp_executesql N'SELECT TOP (1) holy_crap_theres_a_lot_of_columns FROM [chg] LEFT OUTER JOIN [ca_contact] ON [ca_contact].[contact_uuid] = [chg].[affected_contact] ORDER BY [chg].[id] ASC'
=> #<Contact contact_uuid: "xFCxF9xA8xACcx81xAACx86xC9xB1x0ExE3x82xE1v", ... >

事实上,如果我以任何方式强制在 JOIN 子句中进行匹配,它会起作用,但belongs_to似乎使用 WHERE 子句代替,nil是我能得到的最佳响应(很多时候,字符串与其二进制类型之间存在转换错误)。

有没有办法确保默认情况下在belongs_to关联上通过 JOIN 子句进行急切加载?

我发现#find_by_contact_uuidcontact_uuid是主键)工作,而#find由于某种原因没有。这导致这得到了实施。

我最终基本上重写了Active Record提供的关联方法:

module AssociationMethods
  def self.included(base)
    base.reflect_on_all_associations(:belong_to).each do |a|
      define_method a.name do
        # #find_by_<uuid_pk> seems to work where #find doesn't
        a.klass.send "find_by_#{a.association_primary_key}", self[a.foreign_key]
      end
    end
    base.reflect_on_all_associations(:has_many).each do |a|
      define_method a.name do
        a.klass.where(a.foreign_key => self.send(a.association_primary_key))
      end
    end
  end
end
class Contact
  has_many :changes, foreign_key: :affected_contact_id
  include AssociationMethods # include *after* all associations are defined
end
class Change
  belongs_to :affected_contact, class_name: 'Contact'
  include AssociationMethods
end

它没有涵盖 Active Record 在设置关联时提供的所有内容,但它似乎可以解决问题。

使用 includes 应该可以解决您的问题。这是因为includes会根据您的其他条件preloadeager_load

在此处阅读更多内容

最新更新