Ruby on rails Rails:为什么(id:objects)在哪里工作?

Ruby on rails Rails:为什么(id:objects)在哪里工作?,ruby-on-rails,Ruby On Rails,我有以下声明: Customer.where(city_id: cities) SELECT customers.* FROM customers WHERE customers.city_id IN (SELECT cities.id FROM cities... 这将导致以下SQL语句: Customer.where(city_id: cities) SELECT customers.* FROM customers WHERE customers.city_id IN (SELECT

我有以下声明:

Customer.where(city_id: cities)
SELECT customers.* FROM customers WHERE customers.city_id IN (SELECT cities.id FROM cities...
这将导致以下SQL语句:

Customer.where(city_id: cities)
SELECT customers.* FROM customers WHERE customers.city_id IN (SELECT cities.id FROM cities...
这是故意的行为吗?它在什么地方有记录吗?我不会使用上面的Rails代码,而是使用以下代码之一:

Customer.where(city_id: cities.pluck(:id))

这将产生完全相同的SQL语句

它为什么有效

ActiveRecord查询生成器中的某些深层信息非常聪明,可以看出,如果传递数组或查询/条件,它需要构建in子句

这有文件记录吗

2.3.3子集条件 如果要使用IN表达式查找记录,可以将数组传递给条件散列:

Client.where(orders_count: [1,3,5])
此代码将生成如下所示的SQL:

SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))

AREL查询库允许您以快捷方式传入ActiveRecord对象。然后,它会将它们的主键属性传递到它用来联系数据库的SQL中

在查找多个对象时,AREL库将尝试在尽可能少的数据库往返中查找信息。它通过将正在进行的查询作为一组条件保留,直到检索对象为止,来实现这一点

这种方式效率低下:

users = User.where(age: 30).all
#                           ^^^ get all these users from the database
memberships = Membership.where(user_id: users)
#                                       ^^^^^ This will pass in each of the ids as a condition
users = User.where(age: 30)
# This is still a query object, it hasn't asked the database for the users yet.
memberships = Membership.where(user_id: users)
# Note: this line is the same, but users is an AREL query, not an array of users
基本上,这种方式将发出两条SQL语句:

select * from users where age = 30;
select * from memberships where user_id in (1, 2, 3);
其中每一项都涉及到应用程序之间对网络端口的调用,然后通过同一端口传回数据

这将更有效率:

users = User.where(age: 30).all
#                           ^^^ get all these users from the database
memberships = Membership.where(user_id: users)
#                                       ^^^^^ This will pass in each of the ids as a condition
users = User.where(age: 30)
# This is still a query object, it hasn't asked the database for the users yet.
memberships = Membership.where(user_id: users)
# Note: this line is the same, but users is an AREL query, not an array of users
相反,它将构建一个嵌套的查询,因此它只需往返数据库一次

select * from memberships 
where user_id in (
  select id from users where age = 30
);
所以,是的,这是预期的行为。这是Rails的一点魔力,它旨在提高应用程序的性能,而不必知道它是如何工作的

还有一些很酷的优化,比如如果你调用first或last而不是all,它将只检索一条记录

User.where(name: 'bob').all
# SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob'
User.where(name: 'bob').first
# SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob' AND ROWNUM <= 1
或者,如果您设置了一个顺序,并调用last,它将颠倒顺序,然后只获取列表中的最后一条,而不是获取所有记录并只提供最后一条

User.where(name: 'bob').order(:login).first
# SELECT * FROM (SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob' ORDER BY login) WHERE ROWNUM <= 1
User.where(name: 'bob').order(:login).first
# SELECT * FROM (SELECT "USERS".* FROM "USERS" WHERE "USERS"."NAME" = 'bob' ORDER BY login DESC) WHERE ROWNUM <= 1
# Notice, login DESC

使用整数数组转换为IN语句是有意义的,但为什么这也适用于对象?如果cities主键不是id而是其他东西怎么办?@0lli.rocks:在大多数情况下,当您将AR对象传递到查询生成器中时,它将被缩减为其id主键。与Project.finduser类似:u将导致从用户id=123的项目中选择*from。ActiveRecord有很多像这样有用的魔法。