読者です 読者をやめる 読者になる 読者になる

なか日記

一度きりの人生、楽しく生きよう。

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

EntityFrameworkでコードファーストしてる時の話です。

業務アプリ等ではデータがいつ登録、更新されたのかを持たせたりしますよね。

エンティティクラスに登録日時、更新日時なんてメンバーを持たせたものの、これをいちいちビジネスロジックの中で更新するのは超めんどくさい。なんかええ方法ないんかなーと調べていたら、下記サイトにいい方法が載ってました。

これはちょっと感心しました*1

DbContextの派生クラスでSaveChangesメソッドをオーバーライド

以下のコードで登録の時はCreateDateTime、UpdateDateTimeにシステム時刻がセットされます。修正の場合はもちろんUpdateDateTimeのみが更新される仕組みです。

CreateDateTime、UpdateDateTimeプロパティがないエンティティクラスは対象外となりますので例外も発生しません。

public class AppDbContext:DbContext
{
    public DbSet<School> Schools { get; set; }
    public DbSet<Category> Categories { get; set; }

    public override int SaveChanges()
    {
        var now = DateTime.Now;
        SetCreateDateTime(now);
        SetUpdateDateTime(now);
        return base.SaveChanges();
    }

    private void SetUpdateDateTime(DateTime now)
    {
        var entities = this.ChangeTracker.Entries()
            .Where(e => (e.State == EntityState.Added || e.State == EntityState.Modified) && e.CurrentValues.PropertyNames.Contains("UpdateDateTime"))
            .Select(e => e.Entity);

        foreach (dynamic entity in entities)
        {
            entity.UpdateDateTime = now;
        }
    }

    private void SetCreateDateTime(DateTime now)
    {
        var entities = this.ChangeTracker.Entries()
            .Where(e => e.State == EntityState.Added && e.CurrentValues.PropertyNames.Contains("CreateDateTime"))
            .Select(e => e.Entity);

        foreach (dynamic entity in entities)
        {
            entity.CreateDateTime = now;
        }
    }
}

dynamicが活きてますね。すばらしい。

これを応用すればいろいろできますね*2

*1:EF使ってる人にとっちゃ当たり前?

*2:更新ユーザーをセットするとか