Validation 为什么Changeset.change跳过Elixir中的验证?

Validation 为什么Changeset.change跳过Elixir中的验证?,validation,elixir,ecto,changeset,Validation,Elixir,Ecto,Changeset,这是一个用于插入或更新某些数据的简单函数。 如果用户数据已经在数据库中,我只需更新它,否则我将插入一个包含数据的新行。一切正常,但我对验证有问题。 变更集定义: def changeset(struct, params \\ %{}) do struct |> cast(params, [:name, :surname, :user_id]) |> validate_required([:name, :surname, :user_id]) |&g

这是一个用于插入或更新某些数据的简单函数。 如果用户数据已经在数据库中,我只需更新它,否则我将插入一个包含数据的新行。一切正常,但我对验证有问题。 变更集定义:

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, [:name, :surname, :user_id])
    |> validate_required([:name, :surname, :user_id])
    |> unique_constraint(:user_id)
  end
当前仅在插入期间有效,而在更新期间无效

  def add_or_change(user_id, new_data) do
    data_from_db = data_by_user_id (user_id)
    case data_from_db do
      nil ->
        Data.changeset(%Data{}, new_data)
        |> Repo.insert()

      _ ->
        Changeset.change(data_from_db, new_data)
        |> Repo.update()
    end
  end
如果尝试将“”作为:name值插入,则会出现预期的错误(不能为空)。但是,如果使用“”as:name值更新现有行,则变更集不会通过验证,并且我的数据库更新不正确。如何在Repo.update()之前在更改时强制验证?

根据文档:用于内部数据更改,因此它绕过了验证:

该函数用于处理应用程序内部的数据。因此,既不进行验证也不进行铸造。这意味着
change/2
希望更改映射或关键字中的键是原子

您应该使用来应用验证,然后更新验证是否有效。

不要使用此选项:

    Changeset.change(data_from_db, new_data)
只需运行您已经在使用的相同函数:

    Data.changeset(data_from_db, new_data)

顺便说一下,您实际上可以大大简化此函数:

  def add_or_change(user_id, new_data) do
    (data_by_user_id(user_id) || %Data{})
    |> Data.changeset(new_data)
    |> Repo.insert_or_update()
  end