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

时间:2018-03-27 14:51:05

标签: elixir phoenix-framework ecto

这里已经问过How to add timestamps to an existing table with Ecto's timestamps?,但是接受的解决方案意味着每个新条目都有相同的默认时间。我希望新条目具有正确的插入/更新时间。

例如

# 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

如果这是迁移过程中的全部内容, inserted_at的每个 updated_at:my_table都会有2018-01-01 00:00:01作为值,无论插入/更新的日期如何。

我想做的是:

  1. 将日期时间添加到inserted_at&已存在行的updated_at列。
  2. 将时间戳添加到新创建的表时,
  3. inserted_atupdated_at应该是null: false
  4. 以后的条目应该有正确的inserted_at和updated_at值,即inserted_at是行的时间,updated_at是更改的时间,而不是迁移中的默认值。
  5. 我有几个解决方案可以实现这一目标,但它们似乎非常混乱。我正在寻找是否有更简洁的方法来做到这一点,或者是否有办法解决这个案例,我不知道。

    工作迁移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
    

    工作迁移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
    

2 个答案:

答案 0 :(得分:1)

您可以使用fragment将SQL函数提供为默认值。该文档提供以下示例:

create table("posts") do
  add :inserted_at, :naive_datetime, default: fragment("now()")
end

timestamps seems to forward the default: option to add,因此在您的特定情况下,您应该可以执行以下操作:

def change do
  alter table(:my_table) do
    timestamps(default: fragment("now()"))
  end
end

答案 1 :(得分:0)

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

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

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