如何设置阴影属性的默认值 [英] How to set default values for shadow property
问题描述
我有以下实体:
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
}
这是我的数据库上下文
public class PersonDbContext : DbContext
{
private static readonly ILoggerFactory
Logger = LoggerFactory.Create(x => x.AddConsole());
public DbSet<Person> Persons { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseLoggerFactory(Logger)
.UseSqlServer(
"Server=(localdb)\\mssqllocaldb;Database=PersonDb;Trusted_Connection=True;MultipleActiveResultSets=true");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Person>()
.Property<DateTime>("Created")
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAdd();
modelBuilder
.Entity<Person>()
.Property<DateTime>("Updated")
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAddOrUpdate();
}
}
从 OnModelCreating
覆盖中可以看出,我正在将阴影属性更新/创建"添加到 Person
实体.
As can be seen from OnModelCreating
override, I'm adding shadow properties Updated/Created to Person
entity.
我将这些属性设置为使用SQL默认值填充
I set those properties to be populated with SQL default values
- 添加值时
-
已创建
添加或更新值时 -
已更新
Created
when value is addedUpdated
when value is added or updated
下面是客户端代码
var personId = Guid.Parse("CF5EE27D-C694-408A-9F7B-080FF6315843");
using (var dbContext = new PersonDbContext())
{
var person = new Person
{
Id = personId,
Name = "New Person"
};
dbContext.Add(person);
await dbContext.SaveChangesAsync();
}
using (var dbContext = new PersonDbContext())
{
var person = dbContext.Persons.Find(personId);
var personName = person.Name;
person.Name = $"{personName} {DateTime.UtcNow}";
dbContext.SaveChanges();
}
我可以确认插入新个人时,两个属性都设置为UTC日期.但是,在更新时,未设置 Updated
属性.
I can confirm that both properties are set to UTC date when inserting a new person.
However, on update, Updated
property is not being set.
这是生成的t-sql:
This is the t-sql generated:
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[@p1='?' (DbType = Guid), @p0='?' (Size = 4000)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Persons] SET [Name] = @p0
WHERE [Id] = @p1;
SELECT [Updated]
FROM [Persons]
WHERE @@ROWCOUNT = 1 AND [Id] = @p1;
阅读 但是,如果您指定在添加时生成DateTime属性或更新,则必须设置一种生成值的方式.一种方法是配置GETDATE()的默认值(请参见默认值)以生成新行的值.然后,您可以使用数据库触发器以在更新期间生成值(例如以下示例触发器).
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). 我不明白 I don't get what's the purpose of 实际上,如果我将 Indeed, if I change the definition of 并在 这可以完成预期的工作. This does what is expected. 问题是-在EF Core中为阴影属性设置默认值的正确方法是什么. So the question is - what's the proper way to set default values for shadow properties in EF Core. 这是我较大项目中的简化示例,因此对 This is simplified example from my bigger project, so using 我正在使用EF Core 3.1.1 I'm using EF Core 3.1.1 我发现讨论,指出名称 I found dicussion where it is pointed that name @rowanmiller感谢您的快速回复!现在我知道它是如何工作的,但是我认为这有点令人困惑.命名为"ValueGeneratedOnAddOrUpdate"建议在插入和更新时实际生成一个值. @rowanmiller Thanks for the quick reply! Now I know how it works, but
I think it's a bit confusing. The naming "ValueGeneratedOnAddOrUpdate"
suggests that a value actually is generated on insert and update. 文档说:添加时生成的值"添加时生成的值表示如果您不指定值,则会为你." And the docs says: "Value generated on add" "Value generated on add
means that if you don’t specify a value, one will be generated for
you." 添加或更新时生成的值"添加或更新时生成的值表示每次保存记录都会生成一个新值(插入或更新)." "Value generated on add or update" "Value generated on add or update
means that a new value is generated every time the record is saved
(insert or update)." 也许在文档中添加了一个部分,描述了您如何提供自己的文件价值生成器? Maybe add a section in the docs that describes how you supply your own
value generator? 但是,请遵循EF团队的建议 警告部分,并将手动步骤应用于 However, advice from EF team is to follow the warning section and apply manual steps to generate values for Update case manually. @bcbeatty详细说明包含在主要部分中,在Fluent和Data Annotation部分中有一个警告框指向详细说明. @bcbeatty the detailed explanation is included in the main section,
and there is a caution box in the Fluent and Data Annotation sections
that points back to the detailed note. 这只是让EF知道为添加的实体生成了值,它不能保证EF将实际机制设置为产生价值.有关更多详细信息,请参见添加时生成的值. This just lets EF know that values are generated for added entities,
it does not guarantee that EF will setup the actual mechanism to
generate values. See Value generated on add section for more details. 因此,看来至少对于 So it seems, that at least for 这篇关于如何设置阴影属性的默认值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
ValueGeneratedOnAddOrUpdate()
的目的是什么,如果它的行为类似于 ValueGeneratedOnAdd()
,我必须手动干预(创建触发器)设置此属性.ValueGeneratedOnAddOrUpdate()
then, if it behaves like ValueGeneratedOnAdd()
and I have to manually intervene (creating a trigger) to set this property. Updated
shadow属性的定义更改为Updated
shadow property tomodelBuilder
.Entity<Person>()
.Property<DateTime>("Updated")
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAdd();
PersonDbContext
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
foreach (var entry in ChangeTracker.Entries().Where(entity => entity.State == EntityState.Modified))
{
entry.Property("Updated").CurrentValue = DateTime.UtcNow;
}
return base.SaveChanges();
}
OnModelCreating
覆盖中的实体使用 HasData
并不是一个好选择(由于许多实体).HasData
on the entities in OnModelCreating
override is not a good option (due to many entities).<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.1"/>
推荐答案
ValueGeneratedOnAddOrUpdate()
不够描述性.ValueGeneratedOnAddOrUpdate()
is not descriptive enough.
DateTime
阴影属性,OP中的方法才是可行的方法.DateTime
shadow properties, approach in OP is the way to go.