代码之家  ›  专栏  ›  技术社区  ›  Schwern

高效地迭代和变异关联

  •  0
  • Schwern  · 技术社区  · 7 年前

    我们有代码可以有效地做到这一点。

    obj.things.each |thing|
        ... do some stuff ...
    
        obj.things.destroy(thing)
    
        ... do some more stuff...
    end
    

    我们发现,在更改CollectionProxy的同时迭代CollectionProxy只会导致一半的项被迭代。目前,我们正在通过将代理展平为一个数组来解决这个问题。但这意味着复制所有 things 进入记忆。

    obj.things.to_a.each |thing|
        ...
    end
    

    有没有一种方法可以在不将整个关联拉入内存的情况下对集合进行迭代和变异?

    或者,有没有比我们现在使用的更好的模式?例如,每次销毁关联时,包装代码都是我们不想做的事情,所以我们不使用关联挂钩。我们可以编写一个可以使用钩子的子类或范围吗?

    使现代化 : I've posted about the larger issue .

    2 回复  |  直到 7 年前
        1
  •  1
  •   arieljuod    7 年前

    破坏外观中的对象实际上是一种糟糕的做法。

    我可以想出两种方法,您可以将要销毁的对象的ID保存在数组中,或者在数据库中标记它们以删除(添加一个默认为false和do的新布尔列) update_column :to_destroy, true ).

    这样你就可以做这件事。其中(id:ids_to_destroy)。销毁所有(或类似的东西。在哪里销毁:真)。在循环后销毁所有(如果你标记了它们)。

    使用什么方法取决于你的需要。我会选择将ID保存在一个数组中,因为它需要的更改较少,但可能您处理了大量数据,而将一个非常大的数组保存在内存中太多了(这不是常见的情况,因为您只是存储ID,但这是可能的)。

        2
  •  1
  •   matthewd    7 年前

    你的原创 each 已经把整个关联都记起来了。

    使命感 to_a 生成阵列的额外副本(这样就不会发生突变)确实是一种非常合理的方法。而且并不特别昂贵:阵列是重复的,但实际对象不是。

    你也可以使用 ActiveRecord::Base#destroy 相反:

    obj.things.each |thing|
        ... do some stuff ...
    
        thing.destroy
    
        ... do some more stuff...
    end
    

    作为 obj.things 集合不再意识到破坏,它仍将包含完整的东西集,因此迭代将不受影响。(如果 stuff 块正在使用 obj。东西 (不过)