私は木のような構造を作るために自身を参照するエンティティ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を使用すべきかの理解に苦労だと思います。ほとんどのチュートリアルでは、孤立した行をフェッチする方法や、1レベルのプリロードを行う方法の例だけを示しています。私は木のような構造をどのように読み込むべきですか?何か助けてくれてありがとう。
私が見る限り、build_assocは間違って使用されています。単に値をchildrenに設定しないと、クエリの結果にparent_idを含むすべての値が含まれます。 あなたが実際に直面している問題になると、Michalはposgresqlを使用している場合、以下の答えを再帰的に使用します。頻繁に読んで、このテーブルに新しい行を追加することはめったにない場合は、ネストされたセットを使用してください。 –