包括vs加入

时间:2017-03-21 03:24:05

标签: ruby-on-rails activerecord

我有3个模特

  • 用户 - 有很多借记并有很多学分
  • 借记卡 - 属于用户
  • 信用 - 属于用户
借记和贷记非常相似。这些字段基本相同。 我正在尝试对我的模型运行查询以从借方和贷方返回所有字段,其中用户是current_user

User.left_outer_joins(:debits, :credits).where("users.id = ?", @user.id)

正如预期的那样,用户返回所有字段的次数与信用和借记中的记录一样多。

User.includes(:credits, :debits).order(created_at: :asc).where("users.id = ?", @user.id)

它运行了3个查询,我认为应该在一个查询中完成。

这个问题的第二部分是。我怎样才能将记录类型添加到查询中?

在信用记录中会有一个额外的字段来显示信用额度和相同的借方

我已经研究过ActiveRecordUnion gem,但我没看到它会如何解决这个问题

2 个答案:

答案 0 :(得分:3)

parcel无法在一个查询中神奇地检索您想要的所有内容;它将为每个需要命中的模型(通常)运行一个查询。相反,它消除了未来不必要的查询。请看以下示例:

(def data
  [{:start "a" :end "c" :delivery true}
   {:start "d" :end "f" :delivery false}
   {:start "x" :end "y" :delivery true}])

(defn process-parcels
  [[{:keys [start end delivery] :as parcel} & parcels]]
  (if parcel
    (do
      (if delivery
        (println "Parcel Delivered")
        (println "Parcel Collected"))
      (process-parcels parcels))
    (println "Deliveries Completed")))

(process-parcels data)

Parcel Delivered
Parcel Collected
Parcel Delivered
Deliveries Completed
=> nil

这里总共有6个查询,一个用户检索所有用户,然后一个用于循环中的每个includes调用。

好!

users = User.first(5)
users.each do |user|
  p user.debits.first
end

您只会在此处发出两个查询:一个用于用户,另一个用于相关的借记。这就是.debits加速您的应用程序的方式,通过热切地加载您知道自己需要的东西。

至于你的评论,是的,将它们组合成一个表似乎是有意义的。根据您的具体情况,我建议您查看单表继承(STI)。如果你没有采用这条路线,请小心添加名为users = User.includes(:debits).first(5) users.each do |user| p user.debits.first end 的列,Rails不会那样!

答案 1 :(得分:2)

首先,在第一个查询中,通过调用User类上的查询,您要求输入User类型的记录,如果您不想要用户对象,则执行额外的连接可能会很昂贵。 (可能不会)

如果您想要信用卡和借记卡记录,只需在信用卡和借记卡模型上调用查询。如果您在此之前的某处加载用户对象,请使用includes preload eager_load一次性加载关联的信用和借记记录。

在rails中有两种预加载记录的方法。在第一个中,rails对每种类型的记录执行单个查询,第二个rails仅执行一个查询,并使用返回的数据加载不同类型的对象。 includes是一个智能的预加载器,可以执行其中一种方式,具体取决于它认为哪种方式更快。<​​/ p>

如果你想强迫rails使用一个查询,无论如何,eager_load就是你要找的。

请在文章here中阅读有关includeseager_loadpreload的所有内容