如何正确使用 ValueGeneratedOnUpdate()?
How to use ValueGeneratedOnUpdate() correctly?
我正在使用 EF Core 2.1.0-preview1-final CF 方法 和 MS SQL Server 2014并希望自动在一列中设置更新时间戳。我已经使用 ValueGeneratedOnAdd
没有任何问题。当我将新记录插入数据库时,InsertDateTimeUtc
列具有当前 UTC 日期和时间值,UpdateDateTimeUtc
列具有值 0001-01-01 00:00:00.0000000
,因为它是必需的列。
这是我的测试模型(实体class)。
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
设置了另一个值并可以对其进行评估。
我可以找到 that contains following quote which seems to be from this MS doc article - Generated Values。
This just lets EF know that values are generated for added or updated entities, it does not guarantee that EF will setup the actual mechanism to generate values.
但是在提到的 MS 文档文章中我找不到任何关于 ValueGeneratedOnUpdate
用法的信息。我已经尝试使用 ValueGeneratedOnAddOrUpdate
- 也没有成功。
好吧,请问有人提示我如何在代码中不使用任何逻辑(如 person.UpdateDateTimeUtc = DateTime.UtcNow;
)自动为数据库中的列 UpdateDateTimeUtc
设置值吗?或者可以向某人提供 link 我可以阅读更多信息的地方?
Generated values文档主题(问题中提到的link)包含以下警告:
How the value is generated for added and updated entities will depend on the database provider being used. Database providers may automatically setup value generation for some property types, while others will require you to manually setup how the value is generated.
For example, when using SQL Server, byte[] properties that are set as generated on add or update and marked as concurrency tokens, will be setup with the rowversion data type - so that values will be generated in the database. However, if you specify that a DateTime property is generated on add or update, then you must setup a way for the values to be generated. One way to do this, is to configure a default value of GETDATE() (see Default Values) to generate values for new rows. You could then use a database trigger to generate values during updates (such as the following example trigger).
后跟示例触发代码。
所以基本上您应该为更新时的价值生成创建触发器。 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");
我正在使用 EF Core 2.1.0-preview1-final CF 方法 和 MS SQL Server 2014并希望自动在一列中设置更新时间戳。我已经使用 ValueGeneratedOnAdd
没有任何问题。当我将新记录插入数据库时,InsertDateTimeUtc
列具有当前 UTC 日期和时间值,UpdateDateTimeUtc
列具有值 0001-01-01 00:00:00.0000000
,因为它是必需的列。
这是我的测试模型(实体class)。
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 just lets EF know that values are generated for added or updated entities, it does not guarantee that EF will setup the actual mechanism to generate values.
但是在提到的 MS 文档文章中我找不到任何关于 ValueGeneratedOnUpdate
用法的信息。我已经尝试使用 ValueGeneratedOnAddOrUpdate
- 也没有成功。
好吧,请问有人提示我如何在代码中不使用任何逻辑(如 person.UpdateDateTimeUtc = DateTime.UtcNow;
)自动为数据库中的列 UpdateDateTimeUtc
设置值吗?或者可以向某人提供 link 我可以阅读更多信息的地方?
Generated values文档主题(问题中提到的link)包含以下警告:
How the value is generated for added and updated entities will depend on the database provider being used. Database providers may automatically setup value generation for some property types, while others will require you to manually setup how the value is generated.
For example, when using SQL Server, byte[] properties that are set as generated on add or update and marked as concurrency tokens, will be setup with the rowversion data type - so that values will be generated in the database. However, if you specify that a DateTime property is generated on add or update, then you must setup a way for the values to be generated. One way to do this, is to configure a default value of GETDATE() (see Default Values) to generate values for new rows. You could then use a database trigger to generate values during updates (such as the following example trigger).
后跟示例触发代码。
所以基本上您应该为更新时的价值生成创建触发器。 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");