虽然我同意@sheharyar 的观点,即可组合查询是最好的方法,但有时我们需要超越最佳实践的解决方案。因此,我将按照您的说明回答您的问题。
不要让我的示例架构分散您的注意力。这只是我为测试解决方案而加载的一个项目...
要检查查询结构,您可以试试这个:
iex(128)> Map.from_struct(from(q in OneIosThemeGen.Themes.Entry, where: q.base_hex == ^base_hex))
%{
assocs: [],
distinct: nil,
from: {"entries", OneIosThemeGen.Themes.Entry},
group_bys: [],
havings: [],
joins: [],
limit: nil,
lock: nil,
offset: nil,
order_bys: [],
prefix: nil,
preloads: [],
select: nil,
sources: nil,
updates: [],
wheres: [
%Ecto.Query.BooleanExpr{
expr: {:==, [],
[{{:., [], [{:&, [], [0]}, :base_hex]}, [], []}, {:^, [], [0]}]},
file: "iex",
line: 128,
op: :and,
params: [{"#E8EBED", {0, :base_hex}}]
}
]
}
如您所见,where 子句位于wheres 字段中。它包含一个列表。
因此,我们可以从每个查询中提取wheres 字段并连接列表。这就是我在下面演示的内容。
这是一个组合多个查询的 where 子句的示例。它仅通过将 where 子句“和”在一起来处理它们。
base_hex = "#E8EBED"
name = "bodyText"
queries = [
from(q in OneIosThemeGen.Themes.Entry, where: q.base_hex == ^base_hex),
from(q in OneIosThemeGen.Themes.Entry, where: q.name == ^name)
]
build = fn queries ->
wheres = Enum.reduce(queries, [], fn %{wheres: wheres}, acc -> wheres ++ acc end)
from(q in OneIosThemeGen.Themes.Entry)
|> Map.put(:wheres, wheres)
end
query = build.(queries)
rows = Repo.all(query)
# sort function for result equality assertion
sort = fn list -> Enum.sort(list, & &1.id <= &2.id) end
# Single query for results equality test
combined_query = from(q in OneIosThemeGen.Themes.Entry, where: q.base_hex == ^base_hex and q.name == ^name)
rows_combined = Repo.all(combined_query)
# Test that the results are the same
sort.(rows) == sort.(rows_combined)
# true
# Now test that running the queries individually does not return the same results
rows3 = Enum.map(queries, &Repo.all/1) |> List.flatten()
sort.(rows3) != sort.(rows)
# true
IO.puts("length {rows, rows3}: " <> inspect({length(rows), length(rows3)}))
# length {rows, rows3}: {2, 5}
请注意,此解决方案依赖于 Ecto 查询的内部结构,这通常是一种不好的做法。它可能会在未来的 Ecto 更新中中断。但是,这是针对所提出的特定问题的一种潜在解决方案。