【发布时间】:2020-02-17 18:44:21
【问题描述】:
我有以下实体:
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 实体添加阴影属性Updated/Created。
我将这些属性设置为使用 SQL 默认值填充
-
Created加值时 -
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 属性未设置。
这是生成的t-sql:
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;
阅读documentation on genereted value on add or update我看到以下警告:
但是,如果您指定在添加时生成 DateTime 属性 或更新,那么您必须设置一种生成值的方式。 一种方法是配置 GETDATE() 的默认值(请参阅 默认值)为新行生成值。然后你可以使用 数据库触发器在更新期间生成值(例如 以下示例触发器)。
我不明白ValueGeneratedOnAddOrUpdate() 的用途是什么,如果它的行为类似于ValueGeneratedOnAdd(),我必须手动干预(创建触发器)来设置此属性。
确实,如果我将Updated shadow 属性的定义更改为
modelBuilder
.Entity<Person>()
.Property<DateTime>("Updated")
.HasDefaultValueSql("GETUTCDATE()")
.ValueGeneratedOnAdd();
并在PersonDbContext 上覆盖SaveChanges
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();
}
这符合预期。
所以问题是 - 在 EF Core 中为阴影属性设置默认值的正确方法是什么。
这是我更大项目中的简化示例,因此在 OnModelCreating 覆盖中的实体上使用 HasData 不是一个好的选择(因为实体很多)。
我使用的是 EF Core 3.1.1
<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"/>
【问题讨论】:
-
也许this 会有所帮助?