nabehiro ブログ

開発・プログラミングに関して適当に書くブログ

EntityFrameworkで登録日、更新日を自動設定する

Ruby on Rails みたいに、EntiryFramework・CodeFirst で CreatedAt, UpdatedAt を自動設定する方法がないか探してみた。

Adding CreatedDate to an entity using Entity Framework 5 Code First - Stack Overflow

を参考に、DbContext#SaveChanges() 時、
登録レコードは CreatedAt, UpdatedAt に現在日を、更新レコードは UpdatedAt に現在日を指定してます。

public partial class MyDbContext : DbContext
{
    public override int SaveChanges()
    {
        var now = DateTime.Now;
        foreach(var entry in ChangeTracker.Entries().Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
        {
            var type = entry.Entity.GetType();
            if (entry.State == EntityState.Added && HasCreatedAt(type))
                entry.Property("CreatedAt").CurrentValue = now;
            if (HasUpdatedAt(type))
                entry.Property("UpdatedAt").CurrentValue = now;
        }
        return base.SaveChanges();
    }

    private static Dictionary<Type, bool> _entityHasCreatedAtDic = new Dictionary<Type, bool>();
    private static Dictionary<Type, bool> _entityHasUpdatedAtDic = new Dictionary<Type, bool>();
    private bool HasCreatedAt(Type type)
    {
        if (!_entityHasCreatedAtDic.ContainsKey(type))
            _entityHasCreatedAtDic[type] = type.GetProperties().Any(p =>
                p.Name == "CreatedAt" && p.CanWrite && p.PropertyType == typeof(DateTime));
        return _entityHasCreatedAtDic[type];
    }
    private bool HasUpdatedAt(Type type)
    {
        if (!_entityHasUpdatedAtDic.ContainsKey(type))
            _entityHasUpdatedAtDic[type] = type.GetProperties().Any(p =>
                p.Name == "UpdatedAt" && p.CanWrite && p.PropertyType == typeof(DateTime));
        return _entityHasUpdatedAtDic[type];
    }
}