续集宝石:为什么eager()。所有工作但渴望()。首先不是?

时间:2015-09-29 18:07:34

标签: ruby associations eager-loading sequel

我将用户的个人资料字段存储在单独的表中,并希望通过电子邮件地址查找用户(用于密码重置)。试图确定最佳方法,并遇到这种意外的行为不一致。

模式

create_table(:users) do
  String        :username,                  primary_key: true
  ...
end

create_table(:user_fields) do
  primary_key   :id
  foreign_key   :user_id, :users, type: String, null: false
  String        :label, null: false
  String        :value, null: false
end

控制台会话

此版本有效(查找字段,急切加载它的关联用户,调用.all,取第一个):

irb(main):005:0> a = UserField.where(label: 'email', value: 'testuser@test.com').eager(:user).all[0]
I, [2015-09-29T17:54:06.273263 #147]  INFO -- : (0.000176s) SELECT * FROM `user_fields` WHERE ((`label` = 'email') AND (`value` = 'testuser@test.com'))
I, [2015-09-29T17:54:06.273555 #147]  INFO -- : (0.000109s) SELECT * FROM `users` WHERE (`users`.`username` IN ('testuser'))
=> #<UserField @values={:id=>2, :user_id=>"testuser", :label=>"email", :value=>"testuser@test.com"}>
irb(main):006:0> a.user
=> #<User @values={:username=>"testuser"}>

您可以看到两个查询(字段和用户)一起启动,当您尝试访问a.user时,数据已经加载。

但是当我尝试拨打.first代替.all:

irb(main):007:0> b = UserField.where(label: 'email', value: 'testuser@test.com').eager(:user).first
I, [2015-09-29T17:54:25.832064 #147]  INFO -- : (0.000197s) SELECT * FROM `user_fields` WHERE ((`label` = 'email') AND (`value` = 'testuser@test.com')) LIMIT 1
=> #<UserField @values={:id=>2, :user_id=>"testuser", :label=>"email", :value=>"testuser@test.com"}>
irb(main):008:0> b.user
I, [2015-09-29T17:54:27.887718 #147]  INFO -- : (0.000172s) SELECT * FROM `users` WHERE (`username` = 'testuser') LIMIT 1
=> #<User @values={:username=>"testuser"}>

急切加载失败 - 在您尝试使用b.user引用它之前,它不会启动用户对象的第二个查询。

我在这里没有了解续集gem API的内容?什么是基于其关联模型的属性加载模型实例的最佳方法? (通过电子邮件地址查找用户)

1 个答案:

答案 0 :(得分:1)

只有在加载多个对象时才有意义加载。并且为了急切加载,您首先需要所有当前对象,以便在一个查询中获取所有关联对象。使用each,您无法首先访问所有当前对象,因为您正在迭代它们。

如果你希望Sequel在内部为你处理事情,你可以使用eager_each插件,但请注意,它会使dataset.first为急切加载的数据集执行与dataset.all.first类似的操作。但是如果你只需要一个对象,那么最好不要急于加载,如果你需要急切地加载多个对象,最好调用all