如何预先加载has_many
和belongs_to
与Ecto的关联?
例如,在文章has_many
评论和评论belong_to
一篇文章的情况下:
defmodule MyApp.Article do
schema "articles" do
has_many :comments, MyApp.Comments
timestamps
end
end
defmodule MyApp.Comment do
schema "comments" do
belongs_to :article, MyApp.Article
timestamps
end
end
如何在不执行3个单独查询的情况下为每个评论预加载其comments
关联和post
关联的文章创建查询?再次找到每个帖子的第三个似乎是不必要的。
# Does 2 queries to return the Article with `comments` preloaded but not
# the `post` on each Comment
Repo.get!(Article, 123) |> Repo.preload(:comments)
# Does 3 queries to return the Article with `comments` preloaded and
# preloads `post` for each Comment
Repo.get!(Article, 123) |> Repo.preload([:comments, comments: :post])
答案 0 :(得分:0)
你的问题实际上是两件事。
如果你有一对多关系,则不需要“预加载双方”,因为从属表中的所有记录都是指它们所属的一条记录。引入这种循环性会有什么意义?
您希望消除示例中的查询数量。现在您至少有2个查询,因为首先通过发出Repo.get!
向数据库发出请求,然后使用Repo.preload
创建第二个查询。
Ecto中有两种preload
形式 - 您可以在Ecto文档的搜索框中输入“preload”。结果是:
Ecto.Query 预载荷/ 3
Ecto.Repo 预载荷/ 2
第一个用于查询内部。
你使用了第二个,这是文档中说的: “这类似于Ecto.Query.preload / 3,除了它允许你在从数据库中提取模型后预加载模型。”
如果你看一下这个函数的例子,你会发现很明显你需要已经取得的模型(或模型)来用其他值“填充”它。
看起来这不是你想要的 - 你需要摆脱第一个Repo.get
。因此,您需要在查询中使用预加载的形式。
它是这样的:
id = 123
query = from a in Article, where: a.id=^id, preload: [:comments]
query |> Repo.all
请注意,在引用查询中已绑定的变量时,需要使用^
符号。
希望这会有所帮助..