【问题标题】:rails select and includerails 选择并包含
【发布时间】:2011-05-09 08:33:30
【问题描述】:

谁能解释一下?

Project.includes([:user, :company])

这将执行 3 个查询,一个用于获取项目,一个用于获取这些项目的用户,一个用于获取公司。

Project.select("name").includes([:user, :company])

这会执行 3 个查询,并完全忽略选择位。

Project.select("user.name").includes([:user, :company])

这会使用正确的左连接执行 1 个查询。并且仍然完全忽略了选择。

在我看来,rails 忽略了包含包含的选择。好的,但是为什么当我将相关模型放入 select 时,它会从发出 3 个查询切换到发出 1 个查询?

请注意,第 1 个查询是我想要的,我只是无法想象这是获取它的正确方法,也无法想象它为什么会起作用,但我不确定如何在一个查询中获取结果 (.joins似乎只使用了我实际上并不想要的 INNER JOIN,当我手动将连接条件指定为 .joins 时,我们正在使用的搜索 gem 会因为它试图重新添加同名的连接而变得异常)。

【问题讨论】:

标签: ruby-on-rails activerecord ruby-on-rails-3


【解决方案1】:

我在选择和包含方面遇到了同样的问题。 对于关联模型的急切加载,我使用了本机 Rails 范围“预加载”http://apidock.com/rails/ActiveRecord/QueryMethods/preload 它提供了急切的负载,而不会在作用域链上跳过“选择”。

我在这里找到它https://github.com/rails/rails/pull/2303#issuecomment-3889821

希望这个提示对某人有所帮助,因为它对我有帮助。

【讨论】:

  • 这才是真正的答案。 :preloadFTW
【解决方案2】:

好吧,这就是我想出的...

.joins("LEFT JOIN companies companies2 ON companies2.id = projects.company_id LEFT JOIN project_types project_types2 ON project_types2.id = projects.project_type_id LEFT JOIN users users2 ON users2.id = projects.user_id") \
.select("six, fields, I, want")

有效,但它只是让我在一次查询中获得所需的数据。唯一糟糕的部分是我必须给所有东西一个 model2 别名,因为我们使用的是 meta_search,当您指定自己的连接条件时,它似乎无法确定表已经连接。

【讨论】:

  • 我知道这很模糊,但正确的回答是“不要过度优化”。 99% 的时间让它做它的事。
【解决方案3】:

在使用 includeincludes 时,Rails 总是忽略 select 参数。如果您想使用您的 select 参数,请改用 joins

您所说的查询 gem 可能有问题,但您也可以使用 joins 方法包含 sql 片段。

Project.select("name").joins(['some sql fragement for users', 'left join companies c on c.id = projects.company_id'])

我不知道你的架构,所以我不得不猜测确切的关系,但这应该让你开始。

【讨论】:

  • 实际上我的问题更多的是,如果选择被忽略,为什么它会改变查询的运行方式?具体来说,当使用 include 而不选择时,会发出多个查询,oen 用于邮件模型,一个用于每个关联。但是,如果添加了 select,则只对所有数据运行一个查询。我问这个的原因是为了提高性能,我只想为这个数据执行一个查询。而且我试图避免连接,因为它们使用内部连接,或者如果我指定左连接,那么当 meta_search gem 尝试再次添加连接时,它们会导致问题。
  • 您使用的是哪个搜索 gem?
【解决方案4】:

我可能在这里完全遗漏了一些东西,但 selectinclude 不是 ActiveRecord 的一部分。做你想做的事情的通常方法是这样的:

Project.find(:all, :select => "users.name", :include => [:user, :company], :joins => "LEFT JOIN users on projects.user_id = users.id")

查看api documentation 了解更多示例。有时我不得不手动使用find_by_sql

Project.find_by_sql("select users.name from projects left join users on projects.user_id = users.id")

希望这将为您指明正确的方向。

【讨论】:

  • select 和 include 是 Rails 3 查询接口的一部分 guides.rubyonrails.org/active_record_querying.html
  • 我认为可能是这种情况(我还没有深入研究 v3),尽管我在 API 文档中找不到对它们的引用。从我所见,语法似乎有点违反直觉。
【解决方案5】:

我自己也想要这个功能,所以请使用它。 将此方法包含在您的课程中

#ACCEPTS 参数以字符串格式“ASSOCIATION_NAME:COLUMN_NAME-COLUMN_NAME”

def self.includes_with_select(*m)
    association_arr = []
    m.each do |part|
      parts = part.split(':')
      association = parts[0].to_sym
      select_columns = parts[1].split('-')
      association_macro = (self.reflect_on_association(association).macro)
      association_arr << association.to_sym
      class_name = self.reflect_on_association(association).class_name 
      self.send(association_macro, association, -> {select *select_columns}, class_name: "#{class_name.to_sym}")
    end
    self.includes(*association_arr)
  end

您将能够像这样调用:Contract.includes_with_select('user:id-name-status', 'confirmation:confirmed-id'),它会选择那些指定的列。

【讨论】:

    猜你喜欢
    • 2011-05-02
    • 2010-12-02
    • 2012-02-07
    • 2016-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    相关资源
    最近更新 更多