使用Ecto的时间戳将时间戳添加到现有表

Kat*_*ine 7 elixir ecto phoenix-framework

这里有人询问如何使用Ecto的时间戳为现有表添加时间戳?但是,接受的解决方案意味着每个新条目都具有相同的默认时间.我希望新条目具有正确的插入/更新时间.

例如.

# set default to given date to fill in all existing rows with timestamps
def change do
  alter table(:my_table) do
   timestamps(default: "2018-01-01 00:00:01")
  end
end
Run Code Online (Sandbox Code Playgroud)

如果这是迁移中的所有内容,则无论插入/更新的日期如何,每个 inserted_atupdated_atfor :my_table将具有2018-01-01 00:00:01作为值.

我想做的是:

  1. 为预先存在的行添加datetime到inserted_at和updated_at列.
  2. inserted_at并且updated_at应该null: false在将时间戳添加到新创建的表时使用它们.
  3. 将来的条目应该具有正确的inserted_at和updated_at值,即inserted_at是行的生成时间,updated_at是更改的时间,而不是迁移中的默认设置.

我有几个解决方案可以做到这一点,但它们看起来很混乱.我正在寻找是否有更清洁的方法来做到这一点,或者是否有选项来处理这个我错过的案例.

工作迁移1:

def up do
  alter table(:my_table) do
    timestamps(default: "now()")
  end
  execute("ALTER TABLE my_table ALTER COLUMN inserted_at SET DEFAULT now()")
  execute("ALTER TABLE my_table ALTER COLUMN updated_at SET DEFAULT now()")
end

def down do
  alter table(:my_table) do
    remove :inserted_at
    remove :updated_at
  end
end
Run Code Online (Sandbox Code Playgroud)

工作迁移2:

def up do
  alter table(:my_table) do
    timestamps(null: true)
  end
  execute("UPDATE my_table SET inserted_at = now()")
  execute("UPDATE my_table SET updated_at = now()")
  alter table(:my_table) do
    modify :inserted_at, :naive_datetime, null: false
    modify :updated_at, :naive_datetime, null: false
  end
end

def down do
  alter table(:my_table) do
    remove :inserted_at
    remove :updated_at
  end
end
Run Code Online (Sandbox Code Playgroud)

aga*_*ues 0

我遇到了同样的问题。对我来说,这是由于没有timestamps()在 Ecto 模式中指定:

schema "my_table" do
    field(:name, :string)
    ...
    timestamps() // <- Add this here
end
Run Code Online (Sandbox Code Playgroud)

迁移只是告诉您的数据库您有时间戳列。你仍然需要告诉 Ecto 它们的存在!