我有两个表,users
和roles
。我想要做的是在它们之间创建简单的关联,users
可以有多个roles
。
在数据库中它看起来应该是这样的:
作用:
id | name
-----------
1 | ADMIN
2 | USER
用户
id | email | username | roles
-------------------------------------
1 test@gmail.com test [1,2]
到目前为止,我提供了以下代码:
def change do
create table(:users) do
add :email, :string
add :username, :string
add :roles, references(:roles)
end
end
schema "users" do
field :email, :string
field :username, :string
has_many :roles, TimesheetServer.Role
timestamps()
end
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:email, :username])
|> validate_required([:email, :username])
end
def change do
create table(:roles) do
add :name, :string
timestamps()
end
end
schema "roles" do
field :name, :string
belongs_to :users, TimesheetServer.User
timestamps()
end
然后我试图像这样种子数据库:
User.changeset(
%User{},%{email: "test@gmail.com", username: "test", roles: [
%Role{name: "ADMIN"},
%Role{name: "USER"}
]})
|> Repo.insert
不幸的是,这不会在user
表中创建角色列表,也不会在roles
表中保存角色。
非常感谢任何帮助或提示!
答案 0 :(得分:2)
如评论中所述,上述关系必须定义为many_to_many
。为实现这一目标,实际上有两种方式。
首先是将角色架构定义为embedded_schema
,在这种情况下,它将嵌入在父(用户)内。这意味着不会为角色架构创建db表。
第二个选项是通过关联表加入它们。这看起来如下:
迁移:
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_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
现在可以通过以下方式构建关联:
user = Repo.get!(User, user_id) |> Repo.preload(:roles)
role = Repo.get!(Role, role_id)
user_changeset = Changeset.change(user)
|> Changeset.put_assoc(:roles, [role | user.roles])
这将导致有三个表:
用户:
id | email | username |
-------------------------------
1 test@gmail.com test
作用:
id | name
-----------
1 | ADMIN
2 | USER
users_roles:
user_id | role_id
------------------
1 | 1
------------------
1 | 2