使用带子查询的 Ecto 预加载并使用来自主查询的连接

Preload with Ecto with subquery and using a join from the main query

我正在使用 Ecto 从数据库请求数据,我使用以下代码预加载由 [=38= 过滤的 cats ].

Item
|> join(:inner, [i], c in Cat, c.food_category_id == i.id)
|> where([i, c], is_nil(c.price_discount))
|> preload([i, c],
  [
    cats: c,
    cats: :houses
  ])

这很好用,但现在我想按 ID 订购房屋,所以我跳过了这项工作:

Item
|> join(:inner, [i], c in Cat, c.food_category_id == i.id)
|> where([i, c], is_nil(c.price_discount))
|> preload([i, c],
  [
    cats: c,
    cats: [
      houses: from(h in Houses, order_by: h.id)
    ]
  ])

但是没有,这是错误:

from(h in Houses, order_by: h.id()) is not a valid preload expression. preload expects an atom, a list of atoms or a keyword list with more preloads as values. Use ^ on the outermost preload to interpolate a value

唯一 post 有效的方法是使用以下方法之一:

以下作品,使用 ^:

Item
|> join(:inner, [i], c in Cat, c.food_category_id == i.id)
|> where([i, c], is_nil(c.price_discount))
|> preload([i, c],
  ^[
    cats: [
      houses: from(h in Houses, order_by: h.id)
    ]
  ])

这是 Ecto 中的错误吗?

我找到的解决方案是将 |> preload() 一分为二。

Item
|> join(:inner, [i], c in Cat, c.food_category_id == i.id)
|> where([i, c], is_nil(c.price_discount))
|> preload([i, c], [cats: c])
|> preload([cats: [houses: from(h in Houses, order_by: h.id)]])

当您想为预加载及其嵌套预加载提供自定义查询时,您可以使用元组语法,其中第一个元素是主查询,第二个元素是预加载列表,就像您一样会在顶层。

你想要的可以这样实现:

|> preload([i, c], [cats: {c, houses: ^from(h in Houses, order_by: h.id)}])