我正在使用 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;
)吗?或者可以为某人提供一个我可以阅读更多信息的链接?
答案 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");