【问题标题】:many_to_many batch insert/updatemany_to_many 批量插入/更新
【发布时间】:2017-06-09 23:58:10
【问题描述】:

我正在尝试找出保存具有 many_to_many 关系的结构的最佳方法。

假设我通过以下方式创建了 userrole 架构:

迁移:

def change do
 create table(:users) do
   add :email, :string
   add :username, :string
 end

 create table(:roles) do
   add :name, :string, null: false
 end

 create table(:users_roles, primary_key: false) do
  add :user_id, references(:users, on_delete: :delete_all)
  add :role_id, references(:roles, on_delete: :delete_all)
 end

 create unique_index(:users, [:email, :username]
 create unique_index(:roles, [:name])
 create unique_index(:users_roles, [:user_id, :role_id])
end

用户架构:

schema "users" do
  field :email, :string
  field :username, :string
  many_to_many :roles, TimesheetServer.Role, join_through: "users_roles"
 end

  def changeset(struct, params \\ %{}) do
   struct
    |> cast(params, [:email, :username])
    |> validate_required([:email, :username])
  end
end

角色架构:

schema "roles" do
     field :name, :string
     many_to_many :users, TimesheetServer.User, join_through: "users_roles"
   end

   def changeset(struct, params \\ %{}) do
     struct
     |> cast(params, [:name])
     |> validate_required([:name])
   end
 end

在将单个角色与用户关联时,关联没有问题。然而,当涉及到在一个请求中关联多个角色时,我只提出了以下解决方案:

更新用户端点:/api/users/{user_id}

请求正文:

{
  "roles": [
    {"id": 10},
    {"id": 2},
    {"id": 1}
  ]
}

用户变更集:

  def changeset(struct, params \\ %{}) do
     struct
      |> cast(params, [:email, :username])
      |> validate_required([:email, :username])
      |> put_assoc(:roles, cast_roles(params))
  end

  defp cast_roles(params) do
    %{"roles" => roles} = params
    Enum.map(roles, fn role -> get_role(role) end)
  end

  defp get_role(role) do
    %{"id" => id} = role
    Repo.get!(Role, id)
  end

确实有效,关联已更新。我担心的是我必须遍历角色并为每个角色执行数据库请求。有没有其他方法可以达到同样的效果?

【问题讨论】:

  • 我通常为 users_roles 创建一个模块/模式,然后添加一个关联就变成了 Repo.insert %UserRole{user_id: user_id, role_id: role_id}(如果需要,在适当的验证之后)。
  • 那么,在那种情况下,我只需创建多个%UserRole 结构,然后再做Repo.insert_all,对吗?
  • 是的,没错。

标签: elixir phoenix-framework ecto


【解决方案1】:

您可以为指向users_roles 表的关联创建一个模块/架构,然后只需插入一个%UserRole{} 结构来创建UserRole 之间的关联。这样您也可以使用Repo.insert_all 进行批量插入。

defmodule MyApp.UserRole do
  ...
  schema "users_roles" do
    belongs_to :user, User
    belongs_to :role, Role
  end
end
Repo.insert! %MyApp.UserRole{user_id: 123, role_id: 456}

Repo.insert_all! MyApp.UserRole, [%{user_id: 1, role_id: 1},
                                  %{user_id: 2, role_id: 1},
                                  %{user_id: 2, role_id: 2}]

【讨论】:

  • 如果不在 users_roles 架构定义之前添加 @primary_key false,它将无法工作。否则,它会抛出:** (Postgrex.Error) ERROR 42703 (undefined_column): column "id" of relation "users_roles" does not exist
猜你喜欢
  • 2012-02-16
  • 1970-01-01
  • 2016-05-02
  • 2014-06-22
  • 2014-01-16
  • 2011-09-11
  • 2023-03-14
  • 2012-03-19
  • 1970-01-01
相关资源
最近更新 更多