什么是凤凰灵药的变化集

时间:2015-10-17 11:55:56

标签: elixir phoenix-framework ecto

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

有人可以用一种简单的方式详细说明,这样可以帮助其他人来凤凰城。

2 个答案:

答案 0 :(得分:25)

来自documentation

  

变换集允许在操作模型时过滤,转换,验证和定义约束。

     

在Ecto模块的介绍性文档中有一个使用变更集的示例。函数change / 2和cast / 4是创建变更集的常用入口点,而其余函数对于操作它们非常有用。

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

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

来自更改日志:

  

鉴于Repo.update / 2的模型已被弃用,因为它无效并且容易出错,因为无法跟踪更改

就每个型号有多个变更集而言,答案肯定是肯定的。变更集只是一个功能。实际上你甚至没有需要将变更集功能放在你的模型中,但这是放置它们的常用位置。

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

答案 1 :(得分:16)

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

ActiveRecord方法在模型类或实例中执行,而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