Reputation: 453
I have a 3-level hierarchy model relationship, that is, model1
belongs to model2
and model2
belongs to model3
.
I'm trying to preload model2
and model3
for the model1
:
my_models = Repo.all(Model1)
|> Enum.map(fn (x) ->
Repo.preload(x, :model2)
end)
|> Enum.map(fn(x) -> # error "no function clause matching in Ecto.Repo.Preloader.preload/4"
Repo.preload(x.model2, :model3)
end)
The error is "no function clause matching in Ecto.Repo.Preloader.preload/4"
Upvotes: 1
Views: 286
Reputation: 153
Repo.all(from m in Model1, preload: [model2: :model3])
Good article - nested preload in ecto
Upvotes: 0
Reputation: 4081
Repo.preload([{:model2, :model3}])
Should do the trick. You can nest this structure however deep you want. E.g. 5 models deep:
Repo.preload([
{:model1, [
{:model2, [
{:model3, [
{:model4, :model5}
]}
]}
]}
])
Upvotes: 0
Reputation: 84140
You can do:
my_models = Repo.all(Model1) |> Repo.preload(model2: :model3)
Notice that this is not the same as:
my_models = Repo.all(Model1) |> Repo.preload([:model2, :model3])
As explained in https://hexdocs.pm/ecto/Ecto.Query.html#preload/3
If you can provide more of the error message, I'll be able to explain why you are getting that error message. It is likely that model2 (in the 2nd Enum.map
) is nil
, and https://github.com/elixir-ecto/ecto/blob/66e90c97054cd855c7cbb694bc79a0b9313f119b/lib/ecto/repo/preloader.ex#L36 only works with a map
or a list
.
Using the nested preload as above will handle this case for you.
Upvotes: 0