为整个协会建立变更集
Building changeset for entire association
我在这里读到了 cast_assoc/3。但是文档看起来很混乱。我想构建 single changeset for the entire association
并在一个事务中执行它以进行更新。这是我的模特
;
defmodule User do
use Gallery.Web, :model
schema "users" do
field(:name, :string)
field(:occupation, :string)
has_many(:paintings, Painting)
end
def changeset(struct, params \ %{}) do
struct
|> cast(params, [ :name, :occupation ])
|> validate_required([:name, :occupation])
end
end
defmodule Painting do
use Gallery.Web, :model
schema "paintings" do
field(:name, :string)
belongs_to(:users, User)
end
def changeset(struct, params \ %{}) do
struct
|> cast(params, [ :name ])
|> validate_required([:name])
end
end
这是我要构建
的单个变更集的数据
data= %User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: 4606,
name: "Test",
occupation: "Artist",
paintings: [
%Painting{
__meta__: #Ecto.Schema.Metadata<:loaded, "paintings">,
user_id: 4606,
id: 1515,
name: "philip"
},
%Painting{
__meta__: #Ecto.Schema.Metadata<:loaded, "paintings">,
user_id: 4606,
id: 1516,
name: "john"
}
]
}
有什么建议吗?
谢谢
要使变更集正常工作,您的数据需要是普通映射而不是结构(就好像您是从参数中获取的一样)。
如果您只想插入拥有多幅画作的用户,您需要:
- 摆脱结构
- 摆脱 id(如果插入是动态创建的)
- 在用户变更集中有
cast_assoc
像这样:
data = %{
name: "Test",
occupation: "Artist",
paintings: [
%{
name: "philip"
},
%{
name: "john"
}
]
}
%User{}
|> User.changeset(data)
|> Repo.insert
如果您还想以这种方式更新内容,则会变得更加复杂。目前尚不清楚 data
中的绘画列表是否应该更新现有的绘画、添加新的或删除所有以前的绘画并用 data
中的绘画替换它们。我个人不建议使用嵌套的变更集进行更新。 https://hexdocs.pm/ecto/Ecto.Changeset.html#cast_assoc/3
澄清后更新:
要更新所有的绘画,您还需要做两件事。您需要:
- 预加载画作
- 数据中有绘画id
像这样:
data = %{
name: "Test",
occupation: "Artist",
paintings: [
%{
id: 1,
name: "philip"
},
%{
id: 2,
name: "john"
}
]
}
User
|> Repo.get_by(id: user_id)
|> Repo.preload(:paintings)
|> User.changeset(data)
|> Repo.update
您不需要使用 Multi
。这将是一次交易。使用一次Repo
模块通常表示一次数据库操作。
所有的魔法都发生在 paintings: [...]
。根据文档,您有四种情况:
- If the parameter does not contain an ID, the parameter data will be passed to changeset/2 with a new struct and become an insert operation
- If the parameter contains an ID and there is no associated child with such ID, the parameter data will be passed to changeset/2 with a
new struct and become an insert operation
- If the parameter contains an ID and there is an associated child with such ID, the parameter data will be passed to changeset/2 with
the existing struct and become an update operation
- If there is an associated child with an ID and its ID is not given as parameter, the :on_replace callback for that association will be
invoked (see the “On replace” section on the module documentation)
您对第三种情况感兴趣,可以更新到位。如果你没有通过data
所有的画,你可能对第四幅也感兴趣
我在这里读到了 cast_assoc/3。但是文档看起来很混乱。我想构建 single changeset for the entire association
并在一个事务中执行它以进行更新。这是我的模特
;
defmodule User do
use Gallery.Web, :model
schema "users" do
field(:name, :string)
field(:occupation, :string)
has_many(:paintings, Painting)
end
def changeset(struct, params \ %{}) do
struct
|> cast(params, [ :name, :occupation ])
|> validate_required([:name, :occupation])
end
end
defmodule Painting do
use Gallery.Web, :model
schema "paintings" do
field(:name, :string)
belongs_to(:users, User)
end
def changeset(struct, params \ %{}) do
struct
|> cast(params, [ :name ])
|> validate_required([:name])
end
end
这是我要构建
的单个变更集的数据data= %User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
id: 4606,
name: "Test",
occupation: "Artist",
paintings: [
%Painting{
__meta__: #Ecto.Schema.Metadata<:loaded, "paintings">,
user_id: 4606,
id: 1515,
name: "philip"
},
%Painting{
__meta__: #Ecto.Schema.Metadata<:loaded, "paintings">,
user_id: 4606,
id: 1516,
name: "john"
}
]
}
有什么建议吗?
谢谢
要使变更集正常工作,您的数据需要是普通映射而不是结构(就好像您是从参数中获取的一样)。
如果您只想插入拥有多幅画作的用户,您需要:
- 摆脱结构
- 摆脱 id(如果插入是动态创建的)
- 在用户变更集中有
cast_assoc
像这样:
data = %{
name: "Test",
occupation: "Artist",
paintings: [
%{
name: "philip"
},
%{
name: "john"
}
]
}
%User{}
|> User.changeset(data)
|> Repo.insert
如果您还想以这种方式更新内容,则会变得更加复杂。目前尚不清楚 data
中的绘画列表是否应该更新现有的绘画、添加新的或删除所有以前的绘画并用 data
中的绘画替换它们。我个人不建议使用嵌套的变更集进行更新。 https://hexdocs.pm/ecto/Ecto.Changeset.html#cast_assoc/3
澄清后更新:
要更新所有的绘画,您还需要做两件事。您需要:
- 预加载画作
- 数据中有绘画id
像这样:
data = %{
name: "Test",
occupation: "Artist",
paintings: [
%{
id: 1,
name: "philip"
},
%{
id: 2,
name: "john"
}
]
}
User
|> Repo.get_by(id: user_id)
|> Repo.preload(:paintings)
|> User.changeset(data)
|> Repo.update
您不需要使用 Multi
。这将是一次交易。使用一次Repo
模块通常表示一次数据库操作。
所有的魔法都发生在 paintings: [...]
。根据文档,您有四种情况:
- If the parameter does not contain an ID, the parameter data will be passed to changeset/2 with a new struct and become an insert operation
- If the parameter contains an ID and there is no associated child with such ID, the parameter data will be passed to changeset/2 with a new struct and become an insert operation
- If the parameter contains an ID and there is an associated child with such ID, the parameter data will be passed to changeset/2 with the existing struct and become an update operation
- If there is an associated child with an ID and its ID is not given as parameter, the :on_replace callback for that association will be invoked (see the “On replace” section on the module documentation)
您对第三种情况感兴趣,可以更新到位。如果你没有通过data
所有的画,你可能对第四幅也感兴趣