Nim*_*mir 1 elixir ecto phoenix-framework
我有一个简单的before_save转换,并了解到phoenix使用Ecto changest来完成这项任务.
我的Stage模型有一个position属性,默认为current maximum + 1如此尝试实现如下:
舞台模型:
def changeset(struct, params \\ %{}) do
struct
|> cast(params, @required_fields, @optional_fields)
|> validate_required([:name])
|> set_position
end
defp set_position(current_changeset) do
# get current max position from db
max_position = Repo.one(
from s in Stage,
select: fragment("COALESCE(MAX(?),0)", s.position)
)
case current_changeset do
%Ecto.Changeset{valid?: true} ->
put_change(current_changeset, :position, max_position+1)
_ ->
current_changeset
end
end
Run Code Online (Sandbox Code Playgroud)
在逐个插入记录时工作正常但在批量插入时失败; 例如在下面的seed文件中.
种子
alias MyApp.{Repo, Post}
[
%{name: "Requirements"},
%{name: "Quotation"},
%{name: "Development"},
%{name: "Closing"}
]
|> Enum.map(&Post.changeset(%Post{}, &1))
|> Enum.each(&Repo.insert!(&1))
Run Code Online (Sandbox Code Playgroud)
预期/当前行为:
如果说当前最大位置7,对于上面所有插入的4个记录,位置将分别设置为8而不是8,9,10,11!那是因为第一个管道将准备所有的更换然后插入它们!
我播种的方式错了吗?还是变革集?我怎样才能重新设计这个,所以无论我如何进行插入,行为都是一样的?任何反馈,以改善我如何做到这一点表示赞赏!
您可以使用Ecto.Changeset.prepare_changes/2在该变更集的数据库事务中运行任意计算.你的set_position/1函数有正确的参数/返回值(changeset - > changeset),所以你只需要改变:
|> set_position
Run Code Online (Sandbox Code Playgroud)
至
|> prepare_changes(&set_position/1)
Run Code Online (Sandbox Code Playgroud)
而set_position现在在相同的事务中,只是你的帖子被插入之前执行的,而不是同时创建变更被执行.