在 Ecto 中删除关联(对于多对多)
Remove association (for many to many) in Ecto
我有一个具有多对多关联的用户和程序模型。
他们成功地创建了关联,因此一个用户有很多程序(反之亦然),但现在我需要删除关联(但不删除用户或程序)
我在 ProgramController 中有一个函数可以像这样关联它们:
# Myapp.ProgramController
def associate_user(conn, _params) do
%{"_csrf_token" => _csrf_token,"_method"=>_method,"_utf8" => _utf8,"id" => id, "user" => %{"email" => email}} = _params
{pid, _} = Integer.parse(id)
user = Repo.get_by(User, email: email) |> Repo.preload(:programs)
program = Repo.get_by(Program, id: pid) |> Repo.preload(:users)
pid_list = user.programs
|> Enum.map(fn x -> x.id end)
|> List.insert_at(0, program.id)
changeset_list = from(program in Myapp.Program, where: program.id in ^pid_list)
|> Repo.all
|> Enum.map(&Ecto.Changeset.change/1)
from(user in User, where: user.email == ^user.email, preload: [:programs, :role])
|> Repo.one
|> User.changeset(%{})
|> Ecto.Changeset.put_assoc(:programs, changeset_list)
|> Repo.update!
program = conn.assigns[:program]
changeset = Program.changeset(program)
conn
|> put_flash(:info, "Program updated successfully.")
|> redirect(to: program_path(conn, :edit, program))
end
我有一个创建连接的迁移 table
defmodule Myapp.Repo.Migrations.AssociateUsersAndPrograms do
use Ecto.Migration
def change do
alter table(:users) do
add :current_program_id, references(:programs, on_delete: :nilify_all)
end
create table(:users_programs, primary_key: false) do
add :user_id, references(:users, on_delete: :delete_all)
add :program_id, references(:programs, on_delete: :delete_all)
end
create index(:users_programs, [:user_id])
end
end
由于我在 Ecto.Docs 中没有看到 delete_assoc,我该如何解除特定用户与程序的关联?
到目前为止仍在学习和喜爱 Elixir(和 Phoenix),因此非常感谢任何帮助!
您可能需要查看 Ecto.Schema.ManyToMany 文档。有几个选项(直接从文档中获取并重新格式化):
:on_delete
- 删除父记录时对关联采取的操作。
:nothing
(默认)
:delete_all
- 只会从连接源中删除数据,从不删除关联的记录。注意:on_delete 也可以在创建引用时在迁移中设置。如果支持,则首选通过迁移依赖数据库。 :nilify_all
和 :delete_all
不会级联到子记录,除非通过数据库迁移设置。
查看 Ecto's documentation 上的 on_replace 属性。
您只需用 on_replace 属性 标记该字段并像您一直在做的那样调用 Ecto.Changeset.put_assoc,如下所示:
schema "users" do
...
many_to_many :programs, Program, join_through: "users_programs", on_replace: :delete
...
end
文档上不是很清楚。
我有一个具有多对多关联的用户和程序模型。 他们成功地创建了关联,因此一个用户有很多程序(反之亦然),但现在我需要删除关联(但不删除用户或程序)
我在 ProgramController 中有一个函数可以像这样关联它们:
# Myapp.ProgramController
def associate_user(conn, _params) do
%{"_csrf_token" => _csrf_token,"_method"=>_method,"_utf8" => _utf8,"id" => id, "user" => %{"email" => email}} = _params
{pid, _} = Integer.parse(id)
user = Repo.get_by(User, email: email) |> Repo.preload(:programs)
program = Repo.get_by(Program, id: pid) |> Repo.preload(:users)
pid_list = user.programs
|> Enum.map(fn x -> x.id end)
|> List.insert_at(0, program.id)
changeset_list = from(program in Myapp.Program, where: program.id in ^pid_list)
|> Repo.all
|> Enum.map(&Ecto.Changeset.change/1)
from(user in User, where: user.email == ^user.email, preload: [:programs, :role])
|> Repo.one
|> User.changeset(%{})
|> Ecto.Changeset.put_assoc(:programs, changeset_list)
|> Repo.update!
program = conn.assigns[:program]
changeset = Program.changeset(program)
conn
|> put_flash(:info, "Program updated successfully.")
|> redirect(to: program_path(conn, :edit, program))
end
我有一个创建连接的迁移 table
defmodule Myapp.Repo.Migrations.AssociateUsersAndPrograms do
use Ecto.Migration
def change do
alter table(:users) do
add :current_program_id, references(:programs, on_delete: :nilify_all)
end
create table(:users_programs, primary_key: false) do
add :user_id, references(:users, on_delete: :delete_all)
add :program_id, references(:programs, on_delete: :delete_all)
end
create index(:users_programs, [:user_id])
end
end
由于我在 Ecto.Docs 中没有看到 delete_assoc,我该如何解除特定用户与程序的关联?
到目前为止仍在学习和喜爱 Elixir(和 Phoenix),因此非常感谢任何帮助!
您可能需要查看 Ecto.Schema.ManyToMany 文档。有几个选项(直接从文档中获取并重新格式化):
:on_delete
- 删除父记录时对关联采取的操作。:nothing
(默认):delete_all
- 只会从连接源中删除数据,从不删除关联的记录。注意:on_delete 也可以在创建引用时在迁移中设置。如果支持,则首选通过迁移依赖数据库。:nilify_all
和:delete_all
不会级联到子记录,除非通过数据库迁移设置。
查看 Ecto's documentation 上的 on_replace 属性。 您只需用 on_replace 属性 标记该字段并像您一直在做的那样调用 Ecto.Changeset.put_assoc,如下所示:
schema "users" do
...
many_to_many :programs, Program, join_through: "users_programs", on_replace: :delete
...
end
文档上不是很清楚。