使用 ecto 预加载所有链接记录
Preload all linked records using ecto
我有链表这种结构
defmodule Data.Record do
use Data.Web, :model
alias Data.{Record, Repo}
schema "records" do
field(:date_start, :date)
field(:date_end, :date)
field(:change_reason, :string)
field(:is_active, :boolean, default: true)
field(:notes, :string)
belongs_to(
:changed_from,
Data.Record,
foreign_key: :changed_from_id
)
belongs_to(
:changed_to,
Data.Record,
foreign_key: :changed_to_id
)
timestamps()
end
end
但问题是我们需要动态预加载所有嵌套记录。例如,列表可以记录 1 changed_to -> 记录 2 changed_to -> 记录 3 changed_to。但是 ecto doesnt/cant 动态预加载例如 record |> preload([{:changed_to, :changed_to}])
预加载所有链接的 changed_to
记录的最佳 way/workaround 是什么?
好吧,最(脏)的解决方法就是这样。它将 preload
的参数构建到一定深度:
def preload_args(relation, max_level \ 50) do
preload_args(relation, max_level - 1, relation)
end
defp preload_args(_relation, level, acc) when level <= 0, do: acc
defp preload_args(relation, level, acc) do
preload_args(relation, level - 1, [{relation, acc}])
end
使用方法:
Repo.preload record, Record.preload_args(:changed_to)
这将预加载每个 :changed_to
关系到某个级别或直到没有更多。当然,这不是您真正想要使用的解决方案,因为它会为每个预加载执行查询,并且您不知道链会提前多长时间,可能比 50 步长得多。
(请不要因为这个 code/suggestion 烤我,你也特别要求 解决方法 。;)
我认为 by Aetherus, which pointed me to this article 可能会引导您找到更好的解决方案。它还加强了我的假设,即您不需要首先存储父 ID 和子 ID,仅 parent_id 就足够了。这也将使插入新记录变得更容易:您也不需要更新父记录。
我有链表这种结构
defmodule Data.Record do
use Data.Web, :model
alias Data.{Record, Repo}
schema "records" do
field(:date_start, :date)
field(:date_end, :date)
field(:change_reason, :string)
field(:is_active, :boolean, default: true)
field(:notes, :string)
belongs_to(
:changed_from,
Data.Record,
foreign_key: :changed_from_id
)
belongs_to(
:changed_to,
Data.Record,
foreign_key: :changed_to_id
)
timestamps()
end
end
但问题是我们需要动态预加载所有嵌套记录。例如,列表可以记录 1 changed_to -> 记录 2 changed_to -> 记录 3 changed_to。但是 ecto doesnt/cant 动态预加载例如 record |> preload([{:changed_to, :changed_to}])
预加载所有链接的 changed_to
记录的最佳 way/workaround 是什么?
好吧,最(脏)的解决方法就是这样。它将 preload
的参数构建到一定深度:
def preload_args(relation, max_level \ 50) do
preload_args(relation, max_level - 1, relation)
end
defp preload_args(_relation, level, acc) when level <= 0, do: acc
defp preload_args(relation, level, acc) do
preload_args(relation, level - 1, [{relation, acc}])
end
使用方法:
Repo.preload record, Record.preload_args(:changed_to)
这将预加载每个 :changed_to
关系到某个级别或直到没有更多。当然,这不是您真正想要使用的解决方案,因为它会为每个预加载执行查询,并且您不知道链会提前多长时间,可能比 50 步长得多。
(请不要因为这个 code/suggestion 烤我,你也特别要求 解决方法 。;)
我认为