我实施了类似的解决方案,关于如何通过EF Core保存数据时修改创建日期和更新日期的建议,Populate Created and LastModified automagically in EF Core。
void OnEntityStateChanged(object sender, EntityStateChangedEventArgs e)
{
if (e.NewState == EntityState.Modified && e.Entry.Entity is IHasCreationLastModified entity)
entity.LastModified = DateTime.Now;
}
起初,我认为只有在调用SaveChanges()
时才会触发此操作。但显然,它也被称为Entry()
// Get entity
var student = _dbContext.Students.Find(studentId);
// Modify student object
student.Name = "New student name";
// Called Entry(), trigger ChangeTracker.StateChanged
var entry = _dbContext.Entry(student);
// Doesn't trigger ChangeTracker.StateChanged
_dbContext.SaveChanges();
我发现调用ChangeTracker.StateChanged
时触发了_dbContext.Entry(student)
。这样,在调用_dbContext.SaveChanges()
时不会再次触发它。并且还通过了if (e.NewState == EntityState.Modified && e.Entry.Entity is IHasCreationLastModified entity)
以上的条件。
我的假设为什么在调用SaveChanges()
时不会再次触发它,因为在调用Entity()
之后没有新的实体更新。
这将导致在调用LastModified
时而不是在调用.Entry(student)
时分配.SaveChanges()
属性。
在上述情况下调用LastModified
时,是否只能将SaveChanges
属性更新一次?
答案 0 :(得分:1)
我建议您可以在dbContext中覆盖SaveChanges
方法。您可以参考下面我经常使用的代码。
public class ForumContext : DbContext
{
public ForumContext(DbContextOptions<ForumContext> options) : base(options)
{
}
//other settings
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
foreach (var entry in ChangeTracker.Entries())
{
switch (entry.State)
{
case EntityState.Added:
((BaseEntity)entry.Entity).AddedDate = DateTime.Now;
((BaseEntity)entry.Entity).LastModified = DateTime.Now;
break;
case EntityState.Modified:
((BaseEntity)entry.Entity).LastModified = DateTime.Now;
break;
case EntityState.Deleted:
entry.State = EntityState.Modified;
entry.CurrentValues["IsDeleted"] = true;
break;
}
}
return base.SaveChanges(acceptAllChangesOnSuccess);
}
答案 1 :(得分:1)
我想您可能想知道为什么会收到在问题中看到的事件。
执行行student.Name = "New student name";
时,默认情况下,由于EF Core尚未调用ChangeTracker.DetectChanges
方法,所以它什么也不发生。
但是对var entry = _dbContext.Entry(student);
的调用会运行ChangeTracker.DetectChanges
的一个版本-请参阅下面的代码,摘自EF Core代码。
public virtual EntityEntry<TEntity> Entry<TEntity>([NotNull] TEntity entity) where TEntity : class
{
Check.NotNull<TEntity>(entity, nameof (entity));
this.CheckDisposed();
EntityEntry<TEntity> entityEntry = this.EntryWithoutDetectChanges<TEntity>(entity);
//My comment - this runs a version of the DetectChanges method.
this.TryDetectChanges((EntityEntry) entityEntry);
return entityEntry;
}
EF Core的Entry
方法之所以这样做,是因为您可能要求实体的State
,因此它必须调用DetectChanges
以确保其最新。
现在,事实证明,如果您执行以下操作
student.Name = "New student name";
_dbContext.SaveChanges();
然后(在EF Core 5预览版中,但我认为在EF Core 3.1中是相同的),您将获得两个事件。
DetectChanges
触发。SaveChanges
触发,当它设置状态说数据库与实体类匹配时。如果您执行以下操作
student.Name = "New student name";
var entry = _dbContext.Entry(student);
_dbContext.SaveChanges();
然后,您将获得相同的事件。 DetectChanges
会被调用两次(一次被Entry
调用,一次被SaveChanges
调用),但是第二次调用DetectChanges
您可以在我为支持我的书my unit tests而编写的回购中的Entity Framework Core in Action中看到此内容。我正在撰写有关这些事件的部分,找到了您的问题,尽管我会回答。
我希望它可以帮助您了解正在发生的事情,但是我应该说,其他的建议覆盖SaveChanges
的解决方案比使用这些事件更好。