预加载Ecto.Association的两侧

时间:2016-01-19 01:35:48

标签: elixir phoenix-framework ecto

如何预先加载has_manybelongs_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])

1 个答案:

答案 0 :(得分:0)

你的问题实际上是两件事。

  1. 如果你有一对多关系,则不需要“预加载双方”,因为从属表中的所有记录都是指它们所属的一条记录。引入这种循环性会有什么意义?

  2. 您希望消除示例中的查询数量。现在您至少有2个查询,因为首先通过发出Repo.get!向数据库发出请求,然后使用Repo.preload创建第二个查询。

  3. 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

    请注意,在引用查询中已绑定的变量时,需要使用^符号。

    希望这会有所帮助..