【问题标题】:How to do conditional eager_loading in ActiveRecord?如何在 ActiveRecord 中进行条件 eager_loading?
【发布时间】:2015-02-08 22:13:20
【问题描述】:

我有一个模型标签,它是一个树模型(使用 closure_tree),感谢 gem,我可以执行以下操作:

Tag.includes(:children).first

急切地加载它的孩子。现在,我有一个实例方法,它也使用孩子。因此,当我通过上述查询获得标签时,遍历标签及其子项并调用此实例方法,bullet gem 抱怨我正在执行 N+1 查询并建议我使用include(children)。出现这种情况是因为我没有加载children的children,所以在调用实例方法的时候,我对一级标签的每个子标签的children进行了单独的查询。

我可以通过以下方式解决这个问题:

Tag.includes(children: :children).first

在这种情况下,ActiveRecord 急切地加载标签、它的子代和它的子代的子代。但是,如果只有 3 代,这将起作用 - 标签是祖父母,然后是父母(它们是根标签的孩子)和孙子(它们是根标签的孩子的孩子)。如果我有 4 代,那么我必须这样做:

Tag.includes(children: {children: :children}).first

因此,如果我可以确定根标记的最远孙子的depth,有没有办法有条件地构造我的查询 - 如果深度为 2,则使用 includes(:children),如果深度为 3 - 使用 @987654331 @等等?

【问题讨论】:

    标签: ruby-on-rails activerecord eager-loading hashtree


    【解决方案1】:

    https://github.com/mceachen/closure_tree#usage 的文档来看,你应该使用

    Tag.descendants
    Tag.self_and_descendants
    

    这将检索所有的孩子、子孩子等。直到它在叶子上结束。

    【讨论】:

    • 这是确定深度的方法。但是,我不能使用Tag. Includes(:descendants)
    • 但是如果你使用后代,它会一次加载所有子孩子,这样你就不会再有 N+1 查询了,这是你帖子的最初目的吗?
    • 好的,我试试看反馈:)
    • 我今天会给出反馈。
    • 所以这没有成功。执行Tag.includes(:children).find(tag_id) 返回一个普通的标签对象。问题是 - 如果我在上面调用children,它不会调用数据库。 descendants 只返回所有标签的线性数组,这些标签是根的后代,因此不会保留父子关系。
    【解决方案2】:

    我能想到的最佳解决方案是:

      def included_children(tag_id)
        depth = Tag.find(tag_id).leaves.last.depth
        eval(includes_string(depth))
      end
    
      def includes_string(depth)
        "{children: #{depth > 1 ? includes_string(depth - 1) : ':children'}}"
      end
    

    我先找到了最深休假的depth。这告诉我必须调用多少次:children。然后,我根据深度构造一个字符串,并将字符串评估为代码,我在includes 方法中使用它。欢迎任何改进建议,因为这个解决方案有几个缺陷,我觉得它完全不干净。谢谢。

    【讨论】:

    • depth = Tag.find(tag_id).leaves.last.depth 我不认为它会保证你得到最深的叶子。
    • 根据文档:tag.descendants 返回所有子项、子项的子项等的范围,不包括按深度自行排序的范围。而tag.leaves 的作用域是 self_and_descendants 中的所有叶节点。
    • 所以您正在尝试构建将放入包含中的字符串,以便您的包含将包括所有子项和子项,无论深度如何?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    • 2011-07-28
    • 1970-01-01
    • 2020-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多