I am trying to learn the basics of Ecto from Elixir School and I see in their examples that using this syntax Repo.all(from m in Movie, preload: [:actors])
leads to 2 queries being done to the database while using Repo.all(from(m in Movie, join: a in assoc(m, :actors), preload: [actors: a]))
leads to only one query being made to the database, and my question is why does not the first syntax only do 1 query to the database?
Is there another way to fetch the associations in only one database call without the need to be such verbose as in the last syntax?
Example:
I would like to be able query with something likeRepo.all_with_associations(Movie)
or similar, and have only one dtabase call being made to fetch everything…
IEX
First Syntax - Two database calls
iex(42)> Repo.all(from m in Movie, preload: [:actors]
...(42)> )
10:26:40.102 [debug] QUERY OK source="movies" db=0.8ms queue=0.1ms
SELECT m0."id", m0."title", m0."tagline" FROM "movies" AS m0 []
10:26:40.130 [debug] QUERY OK source="actors" db=4.5ms queue=0.1ms
SELECT a0."id", a0."name", m1."id" FROM "actors" AS a0 INNER JOIN "movies" AS m1 ON m1."id" = ANY($1) INNER JOIN "movies_actors" AS m2 ON m2."movie_id" = m1."id" WHERE (m2."actor_id" = a0."id") ORDER BY m1."id" [[1]]
[
%Example.Movie{
__meta__: #Ecto.Schema.Metadata<:loaded, "movies">,
actors: [
%Example.Actor{
__meta__: #Ecto.Schema.Metadata<:loaded, "actors">,
id: 1,
movies: #Ecto.Association.NotLoaded<association :movies is not loaded>,
name: "Tyler Sheridan"
},
%Example.Actor{
__meta__: #Ecto.Schema.Metadata<:loaded, "actors">,
id: 2,
movies: #Ecto.Association.NotLoaded<association :movies is not loaded>,
name: "Gary"
}
],
characters: #Ecto.Association.NotLoaded<association :characters is not loaded>,
distributor: #Ecto.Association.NotLoaded<association :distributor is not loaded>,
id: 1,
tagline: "Something about video games",
title: "Ready Player One"
}
]
Second Syntax - One Database call
iex(43)> query = from(m in Movie, join: a in assoc(m, :actors), preload: [actors: a])
#Ecto.Query<from m in Example.Movie, join: a in assoc(m, :actors),
preload: [actors: a]>
iex(44)> Repo.all(query)
10:28:27.329 [debug] QUERY OK source="movies" db=4.8ms decode=0.1ms queue=0.1ms
SELECT m0."id", m0."title", m0."tagline", a1."id", a1."name" FROM "movies" AS m0 INNER JOIN "movies_actors" AS m2 ON m2."movie_id" = m0."id" INNER JOIN "actors" AS a1 ON m2."actor_id" = a1."id" []
[
%Example.Movie{
__meta__: #Ecto.Schema.Metadata<:loaded, "movies">,
actors: [
%Example.Actor{
__meta__: #Ecto.Schema.Metadata<:loaded, "actors">,
id: 1,
movies: #Ecto.Association.NotLoaded<association :movies is not loaded>,
name: "Tyler Sheridan"
},
%Example.Actor{
__meta__: #Ecto.Schema.Metadata<:loaded, "actors">,
id: 2,
movies: #Ecto.Association.NotLoaded<association :movies is not loaded>,
name: "Gary"
}
],
characters: #Ecto.Association.NotLoaded<association :characters is not loaded>,
distributor: #Ecto.Association.NotLoaded<association :distributor is not loaded>,
id: 1,
tagline: "Something about video games",
title: "Ready Player One"
}
]