考虑以下架构:
defmodule EctoBug.Post do
use Ecto.Schema
import Ecto.Changeset
schema "posts" do
field :title, :string, default: "test"
timestamps()
end
def changeset(post, attrs) do
post
|> cast(attrs, [:title])
|> validate_required([:title])
end
end
Run Code Online (Sandbox Code Playgroud)
如果我做
changeset = EctoBug.Post.changeset(%EctoBug.Post{}, %{title: "test"})
Run Code Online (Sandbox Code Playgroud)
title字段不存在于changes:
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #EctoBug.Post<>, valid?: true>
Run Code Online (Sandbox Code Playgroud)
我找不到任何关于这种行为的信息。
这是一个错误吗?
Ecto 的变更集结构保存应用于模式/结构的变更。默认值未显示为更改的原因是,当您这样做时%EctoBug.Post{},它会填充您在架构上设置的默认值。然后,当您转换参数时,由于字段的原始值和转换值是相同的,所以它并不是真正的更改,也没有这样标记。
如果你这样做
changeset = EctoBug.Post.changeset(%EctoBug.Post{}, %{title: "test"})
Ecto.Changeset.get_field(changeset, :title)
Run Code Online (Sandbox Code Playgroud)
您应该看到标题已设置。虽然Ecto.Changeset.get_change(changeset, :title)会给你 nil 因为它没有从最初给出的原始结构中改变。
如果您提供的值与该字段的默认值不同,title您应该会看到它将作为更改进行跟踪。
因为它是这样工作的,现在如果您有一条尝试更新而不是创建的记录,如果您针对该记录投射一些实际上与它已经拥有的参数相同的参数,ecto 可以跳过尝试更新记录,因为它可以看到什么都没有改变。在插入的情况下,即使没有更改,Ecto 也会尝试插入它。