自动在EF Core中填充创建和LastModified

时间:2018-11-07 09:59:30

标签: c# entity-framework entity-framework-core ef-core-2.1

期待构建一个框架(没有任何存储库模式可直接与DbSets一起使用)以自动填充“创建的”和“最后修改的”,而不是通过代码库散布这些代码。

您能指出正确的方向吗?

  

过去,我尝试将这些填充到构造函数中,但这似乎   就像讨厌的代码一样,每次我们从数据库EF中提取邮件时   更改跟踪会将实体标记为已修改。

.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; }
}

2 个答案:

答案 0 :(得分:10)

从v2.1开始,EF Core提供了State change events

  

Tracked上的新StateChangedChangeTracker事件可用于编写逻辑,以对进入DbContext或更改其状态的实体做出反应。

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

ChangeTracker.Tracked += OnEntityTracked;
ChangeTracker.StateChanged += OnEntityStateChanged;

执行以下操作:

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;
}

答案 1 :(得分:2)

一种可行的解决方案(我们目前正在使用的解决方案)是在DbContext中覆盖SaveChanges()方法,并添加一些代码以遍历设置值的更改实体

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();
}

我们的处境基本上与以下情况类似-在我们的处境中创建的内容可以为空,因此在创建新实体时,代码中的值在创建之前为null(使您易于检查是否曾经填充过Created)。

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