在EF Core中自动填充Created和LastModified

Abh*_*eet 3 c# entity-framework entity-framework-core ef-core-2.1

期待构建一个框架(没有直接使用DbSets的存储库模式)自动填充Created并最后自动修改,而不是通过代码库吐出这些代码.

你能指出我正确的方向如何实现它.

在过去,我尝试在构造函数中填充这些,但是这看起来像是一个讨厌的代码,每次我们从数据库中调出来时,更改跟踪会将实体标记为已修改.

.ctor()
    {
        Created = DateTime.Now;
        LastModified = DateTime.Now;
    }

public interface IHasCreationLastModified
    {
        DateTime Created { get; set; }
        DateTime? LastModified { get; set; }
    }

public class Account : IEntity, IHasCreationLastModified
{
    public long Id { get; set; }

    public DateTime Created { get; set; }
    public DateTime? LastModified { get; set; }
    public virtual IdentityUser IdentityUser { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 15

从v2.1开始,EF Core提供状态更改事件:

New TrackedStateChanged事件on ChangeTracker可用于编写对进入DbContext或改变其状态的实体作出反应的逻辑.

您可以从DbContext构造函数中订阅这些事件

ChangeTracker.Tracked += OnEntityTracked;
ChangeTracker.StateChanged += OnEntityStateChanged;
Run Code Online (Sandbox Code Playgroud)

并做这样的事情:

void OnEntityTracked(object sender, EntityTrackedEventArgs e)
{
    if (!e.FromQuery && e.Entry.State == EntityState.Added && e.Entry.Entity is IHasCreationLastModified entity)
        entity.Created = DateTime.Now;
}

void OnEntityStateChanged(object sender, EntityStateChangedEventArgs e)
{
    if (e.NewState == EntityState.Modified && e.Entry.Entity is IHasCreationLastModified entity)
        entity.LastModified = DateTime.Now;
}
Run Code Online (Sandbox Code Playgroud)

  • @Tolbxela有很多方法可以做到这一点,例如使属性仅获得(甚至是影子)并让 EF Core 通过支持字段来操作它。例如,可以使用“e.Entry.CurrentValues["Created"] = DateTime.Now;”等代替“entity.Created = DateTime.Now;”。 (3认同)

Gib*_*bon 6

一种可能的解决方案(我们当前在我工作的地方使用的解决方案)是重写SaveChanges()DbContext 中的方法并添加一点代码来循环更改实体设置值

public override int SaveChanges()
{
    var changedEntriesCopy = ChangeTracker.Entries()
                .Where(e => e.State == EntityState.Added ||
                e.State == EntityState.Modified ||
                e.State == EntityState.Deleted)
                .ToList();
    var saveTime = DateTime.Now;

        foreach (var entityEntry in changedEntriesCopy)
        {
            if (entityEntry.Metadata.FindProperty("Created") != null && entityEntry.Property("Created").CurrentValue == null)
            {
                entityEntry.Property("Created").CurrentValue = saveTime;
            }

            if (entityEntry.Metadata.FindProperty("Updated") != null)
            {
                entityEntry.Property("Updated").CurrentValue = saveTime;
            }
        }
    return base.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

我们的情况基本上设置类似于 - Created 在我们的情况下是可以为空的,因此当创建一个新实体时,在创建之前的代码中的值为 null(可以轻松检查 Created 是否已填充)。

可能还有其他解决方案,但这是我们最容易设置的解决方案,并且没有任何明显的性能影响

  • 感谢+1,必须将其他答案标记为正确,因为对于“EF Core”来说,这是更优雅的方式。 (2认同)