如何正确使用ValueGeneratedOnUpdate()?

我正在使用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(); 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设置了另一个值,可以对其进行评估。

我可以找到这个SO答案 ,其中包含以下引用,似乎来自这篇MS doc文章 – Generated Values 。

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

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

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

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

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

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

接下来是示例触发器代码。

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

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

 migrationBuilder.CreateTable( name: "Person", columns: table => new { Id = table.Column(nullable: false) .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), InsertDateTimeUtc = table.Column(nullable: false, defaultValueSql: "GETUTCDATE()"), Name = table.Column(nullable: false), UpdateDateTimeUtc = table.Column(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");