Ecto 插入不会自动填充时间戳字段

Ecto insert does not fill timestamp fields automatically

当我尝试使用 Ecto:

向我的数据库中插入一行时
sla = %MyMetrics.MonthlySLA{metric_name: "x", metric_type: "y", value: 43.33, metric_date: Date.new!(2020,1,1)} 
MyMetrics.Repo.insert(sla)

我收到这个错误:

17:44:26.704 [debug] QUERY ERROR db=134.8ms queue=143.8ms idle=1397.2ms
INSERT INTO `monthly_slas` (`metric_date`,`metric_name`,`metric_type`,`value`) VALUES (?,?,?,?) [~D[2020-01-01], "x", "y", #Decimal<43.33>]
** (MyXQL.Error) (1364) (ER_NO_DEFAULT_FOR_FIELD) Field 'inserted_at' doesn't have a default value
    (ecto_sql 3.5.3) lib/ecto/adapters/myxql.ex:241: Ecto.Adapters.MyXQL.insert/6
    (ecto 3.5.5) lib/ecto/repo/schema.ex:649: Ecto.Repo.Schema.apply/4
    (ecto 3.5.5) lib/ecto/repo/schema.ex:262: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4

我的 Ecto 模型。

defmodule MyMetrics.MonthlySLA do

  use Ecto.Schema
  import Ecto.Changeset

  schema "monthly_slas" do
    field :metric_name, :string
    field :metric_type, :string
    field :metric_date, :date
    field :value, :decimal
  end

  def changeset(monthly_sla, params \ %{}) do
    monthly_sla
    |> Ecto.Changeset.cast(params, [:metric_name, :metric_type, :metric_date, :value])
    |> Ecto.Changeset.validate_required([:metric_name, :metric_type, :metric_date, :value])
  end

end

和我的迁移定义:

defmodule MyMetrics.Repo.Migrations.CreateMonthlySla do
  use Ecto.Migration

  def change do
    create table(:monthly_slas) do
      add :metric_name, :string, null: false
      add :metric_type, :string, null: false
      add :metric_date, :date, null: false
      add :value, :decimal, precision: 10, scale: 2, null: false

      timestamps()
    end

    create unique_index(:monthly_slas, [:metric_name, :metric_date])
    create unique_index(:monthly_slas, [:metric_date, :metric_name])
    create unique_index(:monthly_slas, [:metric_type, :metric_name, :metric_date])
    create unique_index(:monthly_slas, [:metric_date, :metric_type, :metric_name])
  end
end

如何解决这个问题?

您需要将 timestamps() 添加到您的 Ecto 模型中。您的迁移定义了 inserted_atupdated_at 字段的架构,但您的代码需要在将模型插入 table 时提供这些字段。这就是 timestamps() 宏的用途。

defmodule MyMetrics.MonthlySLA do

  use Ecto.Schema
  import Ecto.Changeset

  schema "monthly_slas" do
    field :metric_name, :string
    field :metric_type, :string
    field :metric_date, :date
    field :value, :decimal
    # Add this
    timestamps()
  end

  def changeset(monthly_sla, params \ %{}) do
    monthly_sla
    |> Ecto.Changeset.cast(params, [:metric_name, :metric_type, :metric_date, :value])
    |> Ecto.Changeset.validate_required([:metric_name, :metric_type, :metric_date, :value])
  end

end