отношения phoenix ecto при удалении

#relationship #phoenix-framework #ecto

#отношения #phoenix-framework #ecto

Вопрос:

Существует две модели: ресурс и метаданные:

 defmodule Myapp.Repo.Migrations.CreateResources do
  use Ecto.Migration

  def change do
    create table(:resources) do
      add :name, :string
      add :parent_id, references(:resources, on_delete: :delete_all)
      timestamps
    end
    create index(:resources, [:parent_id])
  end
end

defmodule Myapp.Repo.Migrations.CreateMetadata do
  use Ecto.Migration

  def change do
    create table(:metadata) do
      add :size, :integer
      add :resource_id, references(:resources)
      timestamps
    end
    create index(:metadata, [:resource_id])
  end
end

  schema "resources" do
    field :name, :string
    belongs_to :parent, Myapp.Resource
    has_one :metadata, Myapp.Metadata, on_delete: :delete_all
    has_many :childs, Myapp.Resource, foreign_key: :parent_id, on_delete: :delete_all

    timestamps()
  end

  schema "metadata" do
    field :size, :integer
    belongs_to :resource, Myapp.Resource

    timestamps()
  end
 

у ресурса могут быть дочерние элементы, у которых parent_id = id.
также имеет метаданные ресурса. Метаданные таблицы содержат столбец resource_id.
Теперь я хочу удалить ресурс с помощью удаления всех его дочерних элементов и всех связанных метаданных.
когда я пишу

 Repo.delete resource
 

Я получаю сообщение об ошибке:

 [error] #PID<0.441.0> running Myapp.Endpoint terminated
Server: localhost:4000 (http)
Request: POST /resources//docs/test
** (exit) an exception was raised:
    ** (Postgrex.Error) ERROR (foreign_key_violation): update or delete on table "resources" violates foreign key constraint "metadata_resource_id_fkey" on table "metadata"

    table: metadata
    constraint: metadata_resource_id_fkey

Key (id)=(3) is still referenced from table "metadata".
 

это появляется только при срабатывании для удаления метаданных из дочерних ресурсов. Если я попытаюсь удалить ресурс, у которого нет дочерних элементов, тогда все работает правильно.

По-видимому, не приводит к удалению дочерних элементов, необходимых для обратного вызова, удаляющих метаданные, поэтому Postgres выдает ошибку.

Можно ли решить эту проблему, не страдая от метаданных resource_id metadata_id ресурса и не начиная рекурсивное ручное удаление всех дочерних элементов ресурса?

Ответ №1:

:delete_all не переходит каскадом к дочерним записям, если не задано с помощью миграции базы данных. Чтобы устранить проблему, убедитесь, что вы изменили строку сценария переноса метаданных на

 add :resource_id, references(:resources, on_delete: :delete_all)
 

Комментарии:

1. Где есть документация для этого?

2. @Кевин Макдоноу hexdocs.pm/ecto_sql/Ecto.Migration.html#references/2