has_many关联,一列存储多个关联
has_many association, store multiple associations in one column
我有两个 table,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
table 中创建角色列表,也不会在 roles
table.
中保存角色
任何帮助或提示将不胜感激!
如评论中所述,上述关系必须定义为many_to_many
。要做到这一点,实际上有两种方法。
第一个是将角色模式定义为embedded_schema
,在这种情况下它将嵌入到父(用户)中。这意味着不会为角色模式创建数据库 table。
第二种选择是通过协会加入他们table。可以如下所示:
迁移:
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])
这将导致三个 tables:
用户:
id | email | username |
-------------------------------
1 test@gmail.com test
角色:
id | name
-----------
1 | ADMIN
2 | USER
users_roles:
user_id | role_id
------------------
1 | 1
------------------
1 | 2
我有两个 table,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
table 中创建角色列表,也不会在 roles
table.
任何帮助或提示将不胜感激!
如评论中所述,上述关系必须定义为many_to_many
。要做到这一点,实际上有两种方法。
第一个是将角色模式定义为embedded_schema
,在这种情况下它将嵌入到父(用户)中。这意味着不会为角色模式创建数据库 table。
第二种选择是通过协会加入他们table。可以如下所示:
迁移:
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])
这将导致三个 tables:
用户:
id | email | username |
-------------------------------
1 test@gmail.com test
角色:
id | name
-----------
1 | ADMIN
2 | USER
users_roles:
user_id | role_id
------------------
1 | 1
------------------
1 | 2