如何在保存的实体及其 child 属性上使用 Entity Framework 自动设置 CreatedOn 字段

How to automatically set CreatedOn fields with Entity Framework on saved entity and its child properties

每当我调用 databaseContext.SaveChanges() 时,在 Entity Framework 保存数据之前,我需要所有 object 及其 child class 拥有CreatedOn 字段填充了 DateTime.Now().

详细信息:我有一个 BaseEntity class 所有实体都继承自:

 public class BaseEntity
 {
        [Key]
        public virtual Guid Id{ get; set; }
        public DateTime CreatedOn { get; set; }
 }

每当从上面的 BaseEntity 继承的实体被保存时,CreatedOn 属性 被分配 DateTime.Now

这是一个基本存储库:

public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : BaseEntity
{
     ....

     public virtual bool SaveChanges(TEntity entity)
     {            
         if (entity.CreatedOn == DateTime.MinValue)
             entity.CreatedOn = DateTime.Now;
         else
             entity.ModifiedOn = DateTime.Now;

         return _databaseContext.SaveChanges() > 0;           
     }
}

这很好用,但问题是只有 object 本身 CreatedOn 属性 得到更新。任何 child class 可能 不会 更新。

如何更改 SaveChanges() 方法中的逻辑以更新所有 child class 并设置它们的 CreatedOn 日期?

我将提供一个示例来更清楚地说明这一点:假设下面的 User object 实例添加到 dbContext 中,并带有新的 Profile,以及分配新的 Role class 个实例,然后调用 SaveChanges()

public class User: BaseEntity
{
        [Key]
        public virtual Guid Id { get; set; }

        public UserRole Role { get; set; }
        public ProfileDetails Profile { get; set; }
        public DateTime CreatedOn { get; set; }
        public Guid CreatedBy { get; set; }
}

确保为 child user.Role 以及 user.Profile object 分配 CreatedOn 日期的最佳方法是什么(classes也继承自BaseEntity)?我想过使用反射来检查 CreatedOn 字段的 child object 属性,但所有循环都感觉不对。有没有更好的方法?

基本上,您应该在自己的数据库上下文 class 中覆盖 SaveChanges 方法并使用 EF 更改跟踪器获取所有新创建的对象,然后设置它们的 CreatedOn 字段因此。

大致如下:

public class DbContextBase : DbContext 
{
    public override int SaveChanges() 
    {
        DateTime currentDateTime = DateTime.Now;

        // get all the entities in the change tracker - this could be optimized
        // to fetch only the entities with "State == added" if that's the only 
        // case you want to handle
        IEnumerable<DbEntityEntry<BaseEntity>> entities = ChangeTracker.Entries<BaseEntity>();

        // handle newly added entities
        foreach (DbEntityEntry<BaseEntity> entity in entities.Where(e => (e.State == EntityState.Added)) 
        {
            // set the CreatedOn field to the current date&time
            entity.Entity.CreatedOn = currentDateTime;
        }

        // to the actual saving of the data
        return base.SaveChanges();
    }
}

当然你可以改进这个:

  • 还使用 e.State == EntityState.Modified 处理实体并在本例中设置 ModifiedOn 字段
  • 添加一些自定义异常处理来处理常见问题
  • 更多 - 天空和您的想象力是无限的!