phoenix elixir 中的变更集是什么

What is a changeset in phoenix elixir

我在理解模型中的 changeset 时遇到问题。它能做什么?我们可以在一个模型中有多个变更集吗?例如一个用于创建,另一个用于更新。

谁能用简单的方式详细说明一下,以帮助其他来到凤凰城的人。

来自documentation

Changesets allow filtering, casting, validation and definition of constraints when manipulating models..

There is an example of working with changesets in the introductory documentation in the Ecto module. The functions change/2 and cast/4 are the usual entry points for creating changesets, while the remaining functions are useful for manipulating them.

变更集用于创建和修改模型。变更集实际上是一个存储变更集(以及验证规则)的结构。您将变更集传递给 Ecto Repo 以保留有效的变更。

Ecto 的当前主分支在更新时将模型传递给 Repo 时删除了隐式转换,这意味着使用变更集是更新模型的唯一方法。

来自更新日志:

Given a model to Repo.update/2 has been deprecated as it is inneffective and error prone since changes cannot be tracked

就每个模型有多个变更集而言,答案当然是肯定的。变更集只是一个函数。实际上,您甚至 不需要 将变更集函数放入您的模型中,但这是放置它们的常见位置。

如果您在注册用户时需要的字段多于更新用户时需要的字段,那么您可以使用不同的必填字段定义 register_changesetcreate_changeset

如果您稍微熟悉 Rails,ActiveRecord 将数据库访问、查询生成和验证集中在您的模型中,Ecto 将这些职责划分到单独的模块中。

ActiveRecord 方法在模型 class 或实例中执行,而 Ecto 希望您将模型、查询或变更集传递给它的函数。

Ecto 使用变更集来执行验证,而不是在模型内部处理验证。

Ecto 变更集同时提供验证和约束,以防出现问题时最终转化为错误。

它们之间的区别是验证可以在不需要与数据库交互的情况下执行,因此,总是在尝试插入或更新数据库中的条目之前执行。

但是,只有在数据库中执行操作时,才能以安全的方式检查约束。因此,总是在约束之前检查验证。如果验证失败,甚至不会检查约束。

我们来看一个例子:

defmodule User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :name
    field :email
    field :age, :integer
  end

  def changeset(user, params \ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> validate_inclusion(:age, 18..100)
    |> unique_constraint(:email)
  end
end

在上面的 changeset/2 函数中,我们定义了两个验证 - 一个用于检查电子邮件格式,另一个用于检查年龄 - 以及电子邮件字段中的唯一约束。

假设已提供电子邮箱,但年龄无效。变更集会出现以下错误:

changeset = User.changeset(%User{}, %{age: 0, email: "mary@example.com"})
{:error, changeset} = Repo.insert(changeset)
changeset.errors #=> [age: "is invalid"]

在这种情况下,我们没有检查电子邮件字段中的唯一约束,因为数据未通过验证。让我们确定年龄,但假设电子邮件已经存在于数据库中:

changeset = User.changeset(%User{}, %{age: 42, email: "mary@example.com"})
{:error, changeset} = Repo.insert(changeset)
changeset.errors #=> [email: "has already been taken"]

验证和约束定义了检查发生时的明确边界。通过将约束转移到数据库,我们还提供了一种安全、正确且无数据竞争的方法来检查用户输入。

你,可以在这里找到更多细节Ecto Change Set