Elixir 如何在保存回调之前将EXTO变更集设计为true

Elixir 如何在保存回调之前将EXTO变更集设计为true,elixir,phoenix-framework,ecto,Elixir,Phoenix Framework,Ecto,我做了一个简单的前保存转换,并了解到phoenix使用EXTO changest执行此任务 我的阶段模型有一个位置属性,该属性默认为当前最大值+1,因此尝试如下实现: 舞台模型: def changeset(struct, params \\ %{}) do struct |> cast(params, @required_fields, @optional_fields) |> validate_required([:name]) |> s

我做了一个简单的前保存转换,并了解到phoenix使用EXTO changest执行此任务

我的
阶段
模型有一个
位置
属性,该属性默认为
当前最大值+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
逐个插入记录时工作正常,但批量插入失败;例如,在下面的
seed
文件中

种子

alias MyApp.{Repo, Post}

[
  %{name: "Requirements"},
  %{name: "Quotation"},
  %{name: "Development"},
  %{name: "Closing"}
] 
|> Enum.map(&Post.changeset(%Post{}, &1)) 
|> Enum.each(&Repo.insert!(&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
如果当前最大位置为
7
,则对于上面插入的所有4条记录,位置将分别设置为
8
,而不是
8,9,10,11
!这是因为第一个管道将准备所有更改,然后插入它们


我播种的方式错了吗?还是变更集?我如何重新设计它,以便无论我如何进行插入,行为都是相同的?任何反馈,以改善我如何做它是感激的

您可以使用
exto.Changeset.prepare_changes/2
在该变更集的数据库事务中运行任意计算。您的
set\u position/1
函数具有正确的参数/返回值(changeset->changeset),因此您只需更改:

|> set_position


set\u position
现在将在插入Post之前的同一事务中执行,而不是在创建变更集时执行。

您可以使用
exto.changeset.prepare\u changes/2
在该变更集的数据库事务中运行任意计算。您的
set\u position/1
函数具有正确的参数/返回值(changeset->changeset),因此您只需更改:

|> set_position


set_position
现在将在插入帖子之前的同一事务中执行,而不是在创建变更集时执行。

我没有尝试过这一点,但是将
|>set_position
更改为
|>准备变更(&set_position/1)
是否有效?插入记录时,应该在数据库事务中运行
set_position
。使用一个枚举过程应该可以解决这个问题,我认为:
[%{name:“Requirements”}、%{name:“quo引”}、%{name:“Development”}、%{name:“Closing”}>Enum.each(&Post.changeset(%Post{},&1)|>&Repo.insert!)
@Dogbert是的,这很好!谢谢新手问题/1是什么意思,是args的elxir数吗?那么,为什么它会导致没有它的异常呢?请发布一个接受的答案。@AbM你是对的,但我想让changest能够处理我插入的任何记录@Nimir是的,参数的数量。看见即使函数接受0个参数,该值也是必需的
&foo
在Elixir中是无效的语法。我没有尝试过这一点,但是将
|>设置_位置
更改为
|>准备_更改(&set_位置/1)
有效吗?插入记录时,应该在数据库事务中运行
set_position
。使用一个枚举过程应该可以解决这个问题,我认为:
[%{name:“Requirements”}、%{name:“quo引”}、%{name:“Development”}、%{name:“Closing”}>Enum.each(&Post.changeset(%Post{},&1)|>&Repo.insert!)
@Dogbert是的,这很好!谢谢新手问题/1是什么意思,是args的elxir数吗?那么,为什么它会导致没有它的异常呢?请发布一个接受的答案。@AbM你是对的,但我想让changest能够处理我插入的任何记录@Nimir是的,参数的数量。看见即使函数接受0个参数,该值也是必需的<代码>&foo在Elixir中是无效语法。