因此,我正在尝试为所有具有子关联的ecto模型提供模式。
在我的控制器中,有时我只想加载模型,而有时我想用全部或某些关联来加载它。
def get_account!(id), do: Repo.get!(Account, id)
帐户具有以下关联:
has_many :users
belongs_to :company
什么是修改我的get_account的好方法!功能让我可以选择是否预加载关联?
我不想在控制器中使用此预加载代码,我喜欢将所有与查询相关的内容都放在模块本身中,而不希望在控制器中泄漏。
答案 0 :(得分:0)
一种方法是在上下文模块中创建with_<association>
函数,例如:
def get_account!(id), do: Repo.get!(Account, id)
def with_company(%Account{} = account), do: Repo.preload(account, :company)
def with_users(%Account{} = account), do: Repo.preload(account, :users)
因此您可以像这样在控制器中使用它们:
def show(conn, %{"id" => id}) do
account =
Context.get_account!(id)
|> Context.with_company
|> Context.with_users
render(conn, "show.html", account: account)
end
,您在视图中有一个完全可用的帐户。
这种方法的好处是,您可以轻松地通过更具体的预加载来扩展它,例如account |> with_most_active_users(10)
。
答案 1 :(得分:0)
我通常从Rails范围的完成方法中借鉴方法。 Ecto查询接受另一个查询作为源。当所有预加载和其他条件都附加到查询之后,应该调用Repo.get
系列函数,实际上是对数据库执行查询,这是最后一次调用。
因此,您可能会引入像这样的裸模板查询:
defp do_get_account_query(id),
do: from(a in Account, where: a.id == ^id)
并在所有Ecto.Repo.one!/2
查询中使用它:
def get_account!(id, preloads \\ []) do
preloads
Enum.reduce(do_get_account_query(id), fn clause, query ->
Repo.preload(query, clause)
end)
|> Repo.one!()
end
对于更复杂的作用域,可以依赖于泛型函数并从中派生作用域。