elixir - 在 Ecto 中加载树状结构

我有一个实体 Node,它引用自身以创建树状结构。

这是迁移:

create table(:nodes) do
  add :name, :string, null: false, size: 64
  add :parent_id, references(:nodes, on_delete: :nothing)
end

这里是模式定义:

schema "nodes" do
  field :name, :string
  belongs_to :parent, Node
  has_many :children, Node, foreign_key: :parent_id
end

我正在尝试使用这种方法加载整棵树:

root_nodes = Repo.all(
  from n in Node,
    where:  is_nil(n.parent_id) # Root nodes don't have a parent
)

nodes = Enum.map(root_nodes, fn(n) ->
  Ecto.build_assoc(n, :children, load_children(n.id))
end)

地点:

defp load_children(parent_id) do
  nodes = Repo.all(
    from n in Node,
      where: n.parent_id == ^parent_id
  )
  if nodes != [] do
    # If children aren't empty, apply recursively
    nodes = Enum.map(nodes, fn(n) ->
      Ecto.build_assoc(n, :children, load_children(n.id))
    end)
  end

  nodes
end

但我得到:

** (FunctionClauseError) no function clause matching in Ecto.drop_meta/1

一般来说,我想我很难理解应该如何使用 Ecto ORM。大多数教程仅展示了如何获取孤立行或使用一级预加载的示例。我应该如何加载树状结构?感谢您的帮助。

最佳答案

Ecto 不是常规的 ORM,因为大多数 ORM 都试图完全抽象数据库,而 ecto 往往接近底层数据库语义。

这意味着真正的问题不是“如何使用 Ecto 加载树状结构”。但是“我如何使用 SQL 加载树状结构”(假设这就是您使用的)。

毫不奇怪,答案是它非常复杂 - 要么需要对每个嵌套级别进行一次查询(效率极低),recursive queries或更改表示(存储完整路径而不仅仅是 parent_id,或使用 Nested Set model )。

如果您保留 parent_id-only 方法,最简单的方法可能是预先加载所有内容,并在加载到正确位置后适本地拼接(优点是您只执行一个查询)。

虽然这不能直接回答问题(因为没有好的答案),但我希望这能给您一些想法,在哪里寻找解决方案以及如何改变方法以使其更容易。

https://stackoverflow.com/questions/42718549/

相关文章:

python - Django makemessages 写假文件

python - 带注释的水平条形图

flask - 在按钮 onclick location.href 重定向中使用 Flask url

security - 您能否将 AWS 安全组配置为具有子组或嵌套组?

MongoDB 查询 - 按奇数大小过滤数组

python - 如何将备选方案与 python 正则表达式匹配

sql - Oracle SYSDATE 格式更改

css - 使用过多的字体声明是否会对性能产生影响?

spring-mvc - spring-boot自定义404错误页面

php - laravel blade 使用 substr 方法禁用转义