Как автоматически установить поля CreatedOn с Entity Framework на сохраненную сущность и ее дочерние свойства - PullRequest
1 голос
/ 02 февраля 2020

Всякий раз, когда я вызываю databaseContext.SaveChanges(), перед тем, как данные будут сохранены Entity Framework, мне нужно, чтобы все объекты и их дочерние классы имели поле CreatedOn, заполненное DateTime.Now().

Подробности: у меня есть BaseEntity класс, от которого наследуются все сущности:

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

Это работает хорошо, но проблема в том, что обновляется только свойство самого объекта CreatedOn. Любые дочерние классы могут не обновляться .

Как я могу изменить свои логики c в методе SaveChanges(), чтобы обновить все дочерние классы и установить их CreatedOn даты а также?

Я приведу пример, чтобы прояснить это: представьте себе экземпляр объекта User ниже, добавленного к dbContext с новым Profile, а также новым Role назначаются экземпляры класса, а затем вызывается 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; }
}

Каков наилучший способ убедиться, что дата CreatedOn назначена для дочернего объекта user.Role, а также user.Profile объектов (оба классы тоже наследуются от BaseEntity)? Я подумал об использовании Reflection для проверки свойств дочерних объектов для полей CreatedOn, но все циклы выглядят неправильно. Есть ли лучший способ?

1 Ответ

1 голос
/ 02 февраля 2020

По сути, вы должны переопределить метод 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 в данном случае
  • добавить пользовательскую обработку исключений для обработки типичных проблем
  • и многое другое - небо и ваше воображение - это предел!
...