PJS*_*and 9 activerecord ruby-on-rails ruby-on-rails-4 rails-activerecord ruby-on-rails-4.1
我的模型范围略微复杂
class Contact < ActiveRecord::Base
scope :active, -> { where(inactive: false) }
scope :groups, -> { where(contact_type: 2308) }
scope :group_search, -> (query) do
active.groups.where("last_name LIKE '%' + ? + '%'", query)
end
end
Run Code Online (Sandbox Code Playgroud)
出于测试目的,我想确保所有Contacts 未返回的内容group_search都被排除在正确的原因之外.
但要获得该列表,我必须加载
Contact.all - Contact.group_search('query')
Run Code Online (Sandbox Code Playgroud)
它运行两个查询,返回一个Array而不是一个Relation,并且比我想要的慢.
而且由于我正在测试group_search范围,因此编写另一个负面的范围会破坏这一点.我宁愿做一些像:
Contact.merge.not(Contact.group_search('query'))
Run Code Online (Sandbox Code Playgroud)
生成以下SQL查询:
SELECT *
FROM contacts
WHERE NOT (contact_type = 2308 AND inactive = 0 AND last_name LIKE '%' + ? + '%')
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点?
Ana*_*mez 10
要否定范围,您可以使用:
Contact.where.not(id: Contact.group_search('query'))
Run Code Online (Sandbox Code Playgroud)
这与使用pluck(在其中一条评论中提出)不同:
Contact.where.not(id: Contact.group_search('query').pluck(:id))
Run Code Online (Sandbox Code Playgroud)
没有pluck,它会产生一个查询(有两个选择):
SELECT `contacts`.* FROM `contacts` WHERE `contacts`.`id` NOT IN (SELECT `contacts`.`id` FROM `contacts` WHERE `contacts`.`group_search` = 'query')
Run Code Online (Sandbox Code Playgroud)
使用pluck,它会产生两个独立的查询:
SELECT `contacts`.`id` FROM `contacts` WHERE `contacts`.`group_search` = 'query'
SELECT `contacts`.* FROM `contacts` WHERE `contacts`.`id` NOT IN (1, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361)
Run Code Online (Sandbox Code Playgroud)
查询许多记录时,第一个记录的效率更高.当然Contact.where.not(group_search: 'query')效率更高,因为它使用一个选择产生一个查询(但在某些情况下这可能是不可能的):
SELECT `contacts`.`id` FROM `contacts` WHERE `contacts`.`group_search` != 'query'
Run Code Online (Sandbox Code Playgroud)
我认为你正在寻找的是否定范围,你可以使用where_values(或where_values_hash在Rails> = 5):
conditions = Contact.group_search('query').where_values
@contacts = Contact.where.not(conditions.reduce(:and))
Run Code Online (Sandbox Code Playgroud)
要使此解决方案在Rails 4.x中工作,您应该在作用域中提供值作为数组:
scope :groups, -> { where(contact_type: [2308]) }
Run Code Online (Sandbox Code Playgroud)
我也发现了一个简洁的通用实现来否定范围,你也可能会发现它很有趣.
在 Rails 6 中,枚举值上添加了负范围。
你可以这样使用它:
Contact.not_active
Contact.not_groups
Contact.not_group_search
Run Code Online (Sandbox Code Playgroud)
相关拉取请求
| 归档时间: |
|
| 查看次数: |
7516 次 |
| 最近记录: |