如何正确使用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");