ruby-on-rails 轨迹选择并包括

lvmkulzt  于 2022-11-26  发布在  Ruby
关注(0)|答案(6)|浏览(183)

有人能解释一下吗?

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

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

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

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

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

这将执行1个带有正确左连接的查询,并且仍然完全忽略select。
在我看来,Rails忽略了带有includes的select。好吧,但是为什么当我把一个相关的模型放在select中时,它会从发出3个查询切换到发出1个查询呢?
请注意,1查询是我想要的,我只是无法想象这是正确的方式来获得它,也不知道为什么它的工作,但我不知道如何在一个查询中获得结果(.joins似乎只使用内部连接,我实际上并不想要,当我手动指定连接条件给.joins时,我们正在使用的搜索gem吓坏了,因为它试图重新添加同名的连接)。

fjnneemd

fjnneemd1#

我在select和includes中也遇到了同样的问题。对于关联模型的急切加载,我使用了本机Rails作用域“preload”http://apidock.com/rails/ActiveRecord/QueryMethods/preload,它提供了急切加载,而不会在作用域链中跳过“select”。
我在这里找到的https://github.com/rails/rails/pull/2303#issuecomment-3889821
希望这条建议对别人有帮助,就像对我有帮助一样。

a64a0gku

a64a0gku2#

好吧,这是我想到的......

.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,当你指定自己的连接条件时,它似乎无法判断一个表是否已经连接。

iecba09b

iecba09b3#

Rails在使用includeincludes时总是忽略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'])

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

jhkqcmku

jhkqcmku4#

这里我可能遗漏了一些东西,但是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")

希望这能给你指明正确的方向。

9njqaruj

9njqaruj5#

我自己也想要这个功能,所以请使用它。在您的类中包含这个方法
字符串格式的#ACCEPTS参数“关联名称:列名称-列名称”

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'),它将选择那些指定的列。

p5fdfcr1

p5fdfcr16#

preload解决方案似乎不像eager_loadincludes那样执行JOIN操作,因此为了获得最佳效果,我也编写了自己的解决方案,并将其作为我维护的与数据相关的gem**The Brick**的一部分发布。
通过像这样覆盖ActiveRecord::Associations::JoinDependency.apply_column_aliases()****,当您添加.select(...)时,它可以充当筛选器,以选择构建哪些列别名。
加载了gem 'brick'之后,为了启用这种选择性行为,添加特殊列名:_brick_eager_load作为.select(...)中的第一个条目,这将在构建别名时启用列过滤。

Employee.includes(orders: :order_details)
        .references(orders: :order_details)
        .select(:_brick_eager_load,
                'employees.first_name', 'orders.order_date', 'order_details.product_id')

由于外键对于正确关联所有内容是必不可少得,因此它们是自动添加得,因此您不需要将它们包括在选择列表中.
希望它可以保存您的查询时间和一些内存!

相关问题