Sequel gem:为什么 eager().all 有效而 eager().first 无效?
Sequel gem: Why does eager().all work but eager().first doesn't?
我将用户的个人资料字段存储在单独的 table 中,并希望通过电子邮件地址查找用户(用于密码重置)。试图确定最佳方法,并且 运行 陷入这种意外的行为不一致。
架构
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 引用它之前,它不会启动对用户对象的第二次查询。
我对这里的 sequel gem API 有什么不理解的?根据关联模型的属性加载模型实例的最佳方式是什么? (通过电子邮件地址查找用户)
预加载仅在加载多个对象时才有意义。为了预先加载,您首先需要所有当前对象,以便在一次查询中获取所有关联对象。使用 each
,您无法首先访问所有当前对象,因为您正在迭代它们。
如果您希望 Sequel 为您处理内部事务,您可以使用 eager_each
插件,但请注意,它会让 dataset.first
做类似于 dataset.all.first
的事情急切加载的数据集。但是如果你只需要一个对象最好不要急切加载,如果你需要急切加载多个则调用all
。
我将用户的个人资料字段存储在单独的 table 中,并希望通过电子邮件地址查找用户(用于密码重置)。试图确定最佳方法,并且 运行 陷入这种意外的行为不一致。
架构
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 引用它之前,它不会启动对用户对象的第二次查询。
我对这里的 sequel gem API 有什么不理解的?根据关联模型的属性加载模型实例的最佳方式是什么? (通过电子邮件地址查找用户)
预加载仅在加载多个对象时才有意义。为了预先加载,您首先需要所有当前对象,以便在一次查询中获取所有关联对象。使用 each
,您无法首先访问所有当前对象,因为您正在迭代它们。
如果您希望 Sequel 为您处理内部事务,您可以使用 eager_each
插件,但请注意,它会让 dataset.first
做类似于 dataset.all.first
的事情急切加载的数据集。但是如果你只需要一个对象最好不要急切加载,如果你需要急切加载多个则调用all
。