【发布时间】:2022-06-17 17:42:55
【问题描述】:
我有一张桌子A 和has_one 桌子B 和C。
我正在对A 进行查询,但是,根据请求的列,我希望能够从B 和/或C 获取join 和preload 列。
对于连接,我认为这很容易,它们可以在调用Repo.all 之前动态链接到查询。但是如何处理预加载?根据查询中是否需要表B 和C,preload 应该有不同的参数,或者根本不应该存在。
【问题讨论】:
我有一张桌子A 和has_one 桌子B 和C。
我正在对A 进行查询,但是,根据请求的列,我希望能够从B 和/或C 获取join 和preload 列。
对于连接,我认为这很容易,它们可以在调用Repo.all 之前动态链接到查询。但是如何处理预加载?根据查询中是否需要表B 和C,preload 应该有不同的参数,或者根本不应该存在。
【问题讨论】:
我建议的解决方案是动态创建预加载列表并将其传递给 preload()。
对我来说发送到后端的请求结构是这样的:
{
limit: 10,
offset: 0,
preloads: {"research_status": null, "assets": null, "notes": null, "job_applications": {"job_position": null, "status": null, "discarded_reason_var": null}}
}
在上述请求示例中,User 实体与 research_status、assets、notes 和 job_applications 相关联。 job_applications 再次与 job_position、status 和 notes 关联。
我创建了一个辅助函数来解析 args 中的“预加载”,(你可以在任何地方进行,我在控制器中进行):
def parse_query_preloads(%{"preloads" => preloads} = params) do
preloads
|> Jason.decode!()
|> build_preloads()
|> (&Map.put(params, "preloads", &1)).()
end
def parse_query_preloads(params), do: params
defp build_preloads(preload_map),
do:
preload_map
|> Enum.map(fn
{preload, sub_preload} when not is_nil(sub_preload) and is_map(sub_preload) ->
[{preload |> String.to_atom(), build_preloads(sub_preload)}]
|> Enum.into([])
{preload, nil} ->
preload
|> String.to_atom()
end)
像这样在控制器中解析参数:
params =
params
|> parse_query_preloads()
最后在我的查询中,我会简单地使用 params["preloads"] 并在预加载函数中使用它们。
User
|> preload(^params["preloads"])
|> limit(^params["limit"])
|> offset(^params["offset"])
|> Repo.all()
这将使查询中的预加载动态化。我希望这能解决您的问题,如果有错误/改进,请告诉我。
【讨论】: