如何正确使用ValueGeneratedOnUpdate()?

时间:2018-04-03 16:09:21

标签: c# ef-code-first entity-framework-core

我正在使用 EF Core 2.1.0-preview1-final CF方法 MS SQL Server 2014 ,并希望在一个时间戳中设置更新时间戳列自动。我已经使用ValueGeneratedOnAdd而没有任何问题。当我将新记录插入我的数据库时,InsertDateTimeUtc列具有当前的UTC日期和时间值,UpdateDateTimeUtc列的值为0001-01-01 00:00:00.0000000,因为它是必需的列。

这是我的测试模型(实体类)。

public class Person
{
    public string Name { get; set; }

    public DateTime InsertDateTimeUtc { get; set; }

    public DateTime UpdateDateTimeUtc { get; set; }


    public static void OnModelCreating(ModelBuilder modelBuilder)
    {
        var entity = modelBuilder.Entity<Person>();

        entity.Property(p => p.Name)
              .IsRequired();

        entity.Property(p => p.InsertDateTimeUtc)
              .HasDefaultValueSql("GETUTCDATE()")
              .ValueGeneratedOnAdd()
              .IsRequired();

        entity.Property(p => p.UpdateDateTimeUtc)
              .HasDefaultValueSql("GETUTCDATE()")
              .ValueGeneratedOnUpdate()
              .IsRequired();
    }
}

据我测试ValueGeneratedOnUpdate并不像我预期的那样有效。如果我更新记录,我希望列UpdateDateTimeUtc将获得当前的UTC日期和时间值,但它不会更改。记录(属性Name)将成功更新 - 我为属性Name设置了另一个值,可以对其进行评估。

我可以找到包含以下引用的this SO answer MS doc article - Generated Values

  

这只是让EF知道为添加或更新的实体生成的值,它不能保证EF会设置生成值的实际机制。

但在提到的MS doc文章中,我找不到有关ValueGeneratedOnUpdate用法的任何信息。我已经尝试使用ValueGeneratedOnAddOrUpdate - 但也没有成功。

嗯,有人提示如何在代码中自动为数据库UpdateDateTimeUtc设置值而不需要代码中的任何逻辑(如person.UpdateDateTimeUtc = DateTime.UtcNow;)吗?或者可以为某人提供一个我可以阅读更多信息的链接?

1 个答案:

答案 0 :(得分:3)

Generated values文档主题(问题中提到的链接)包含以下警告:

  

如何为添加和更新的实体生成值取决于所使用的数据库提供程序。数据库提供程序可能会自动为某些属性类型设置值生成,而其他提供程序则需要您手动设置值的生成方式。

     

例如,在使用SQL Server时,将设置为在添加或更新时生成并标记为并发令牌的byte []属性,将使用rowversion数据类型进行设置 - 以便在数据库中生成值。 但是,如果指定在添加或更新时生成DateTime属性,则必须设置一种方法来生成值。一种方法是配置GETDATE()的默认值(请参阅默认值)以生成新行的值。然后,您可以使用数据库触发器在更新期间生成值(例如以下示例触发器)。

后面是示例触发器代码。

所以基本上你应该在更新时创建值生成触发器。更新记录后,EF Core将只读回数据库中的值(类似于标识和计算列)。

在您的示例中,修改生成的迁移Up方法,如下所示:

migrationBuilder.CreateTable(
    name: "Person",
    columns: table => new
    {
        Id = table.Column<int>(nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        InsertDateTimeUtc = table.Column<DateTime>(nullable: false, defaultValueSql: "GETUTCDATE()"),
        Name = table.Column<string>(nullable: false),
        UpdateDateTimeUtc = table.Column<DateTime>(nullable: false, defaultValueSql: "GETUTCDATE()")
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_Person", x => x.Id);
    });

// Add the following:   
migrationBuilder.Sql(
@"CREATE TRIGGER [dbo].[Person_UPDATE] ON [dbo].[Person]
    AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;

    DECLARE @Id INT

    SELECT @Id = INSERTED.Id
    FROM INSERTED

    UPDATE dbo.Person
    SET UpdateDateTimeUtc = GETUTCDATE()
    WHERE Id = @Id
END");