我有一個實體Node
,它引用自身以創建樹狀結構。在Ecto中加載樹狀結構
這裏是遷移:
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
一般情況下,我想我與外生ORM應如何使用的理解鬥爭。大多數教程僅顯示如何提取隔離行或使用一個預加載級別的示例。我應該如何加載一個樹狀結構?感謝您的任何幫助。
阿薩就我所看到的,build_assoc使用不當。爲什麼不簡單地將該值設置爲:children,查詢結果包含所有值,包括parent_id。 當談到你實際面臨的問題時,Michal的答案如下 - 使用遞歸查詢如果你使用posgresql。如果您經常閱讀並且很少在此表中添加新行,請使用嵌套集。 –