【问题标题】:Preloading Ecto Associations by default默认情况下预加载 Ecto 关联
【发布时间】:2015-06-18 04:17:35
【问题描述】:

有没有办法在不显式使用 preload: 的情况下预加载 ecto 关联?

类似于架构中的选项?

schema "gadgets" do
  field :foo,
  has_many :bars, Myapp.Bar, preload: true
end

我正在做类似的事情

Repo.get(Gadget, id)
  |> Repo.preload: [:bars]

编辑:我尝试这样做的原因是因为我想将相关模型预加载到已经预加载的相关模型中,例如

 preload: [:invoices preload: :items] 

【问题讨论】:

    标签: elixir ecto


    【解决方案1】:

    您还可以将预加载作为查询的一部分:

    defmodule Gadget do
      use Ecto.Model
    
      # ...
    
      def with_invoices(query) do
        from q in query, preload: [invoices: :items]
      end
    end
    

    然后:

    Gadget
    |> Gadget.with_invoices
    |> Repo.get!(id)
    

    【讨论】:

    • 是否有任何理由它不是架构中的选项?我知道在查询时保留是否预加载的选项很好,但对于某些相关模型,您总是需要预加载它。在我的,发票总额是根据项目计算的,如果没有预加载,它将无法工作。
    【解决方案2】:

    我不确定这是不是最快的方法,但我最终使用 after_load 回调执行此操作,如下所示:

    defmodule Invoice do
      use Ecto.Model
    
      after_load :preload_items
    
      def preload_items(invoice) do
        invoice |> Repo.preload([:items])
      end
    end
    

    现在,每次加载 Invoice 时,即使它是由其他东西预加载的,它也会预加载其关联的项目。

    编辑 - 不要这样做

    改为将预加载放在查询中。使用上述代码检索 1000 张发票将导致 1 + 1000 次查询。查询中的预加载添加了 0NE。 询问。 1 + 1

      query = from c in Gadget,
      #retrieve nested associations adds one query
      preload: [invoices: :items]
      select c
    
    Repo.all(query)
    

    【讨论】:

    • 不要这样做。这将对每张发票进行查询。因此,如果您在查询中加载 10 个发票,它将执行 10 个单独的查询来加载项目。
    • 回调已从 Elixir 中移除
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多