web-dev-qa-db-ja.com

Entity Framework 5 Code Firstを使用してエンティティにCreatedDateを追加する

モデルのエンティティにCreatedDateプロパティを追加しようとしていますが、EF5 Code Firstを使用しています。この日付は一度設定すると変更されず、UTC日付になります。モデルにはCreatedDateプロパティを含む抽象クラスから継承したい多くのエンティティがあるため、コンストラクターを使用したくありません。また、インターフェイスでコンストラクターを強制することはできません。

さまざまなデータアノテーションを試し、特定のエンティティタイプを選択し、正しいtable_nameおよびcolumn_namegetdate()デフォルト値を使用してalter制約を記述するデータベース初期化子を記述しようとしましたが、そのコードを正しく書くことができます。

AuditDbContext-Entity Framework Auditing Context または EntityFramework.Extended ツールを参照しないでください。これらはここで必要なことを実行しないためです。

[〜#〜] update [〜#〜]

SaveChanges()CreatedDateはnullです。ViewModelをビューに渡しているため、ビューにはCreatedDateという監査プロパティが正しくありません。また、モデルをビューに渡しても、ビューのCreatedDateを編集または保存していません。

ここ を読んで、[DatabaseGenerated(DatabaseGeneratedOption.Identity)]を追加できます。これにより、EFにCreatedDateを挿入および更新後に正しく保存するように指示されますが、 application:ただし、この属性を追加するとCannot insert explicit value for identity column in table when IDENTITY_INSERT is set to OFFエラーが発生します。

この単純なデータベース要件はCode Firstで実装するのはばかげているので、EF Model Firstに切り替えようとしています。

29
Brian Ogden

ここに私がそれをした方法があります:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedDate{ get; set; }

私の移行のUp()メソッドで:

AddColumn("Agents", "CreatedDate", n => n.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
69
Rusty Divine

コンテキストでSaveChanges-Methodをオーバーライドします。

public override int SaveChanges()
{
  DateTime saveTime = DateTime.UtcNow;
  foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == (EntityState) System.Data.EntityState.Added))
   {
     if (entry.Property("CreatedDate").CurrentValue == null)
       entry.Property("CreatedDate").CurrentValue = saveTime;
    }
    return base.SaveChanges();

}

コメントのため更新:新しく追加されたエンティティのみに日付が設定されます。

28
Stephan Keller

Stephans's Answer に似ていますが、 Reflection で、すべてのユーザー(外部)更新を作成/更新時間も無視します。 要点を表示

  public override int SaveChanges()
        {
            foreach (var entry in ChangeTracker.Entries().Where(x => x.Entity.GetType().GetProperty("CreatedTime") != null))
            {
                if (entry.State == EntityState.Added)
                {
                    entry.Property("CreatedTime").CurrentValue = DateTime.Now;
                }
                else if (entry.State == EntityState.Modified)
                {
                    // Ignore the CreatedTime updates on Modified entities. 
                    entry.Property("CreatedTime").IsModified = false;
                }

                // Always set UpdatedTime. Assuming all entities having CreatedTime property
                // Also have UpdatedTime
                // entry.Property("UpdatedTime").CurrentValue = DateTime.Now;
                // I moved this part to another foreach loop
            }

            foreach (var entry in ChangeTracker.Entries().Where(
                e => 
                    e.Entity.GetType().GetProperty("UpdatedTime") != null && 
                    e.State == EntityState.Modified || 
                    e.State == EntityState.Added))
            {
                entry.Property("UpdatedTime").CurrentValue = DateTime.Now;
            }

            return base.SaveChanges();
        }
4
guneysus

ここでの主要な問題は、SaveChangesを呼び出すたびにCreatedDateが更新され、CreatedDateをビューに渡さなかったため、Entity FrameworkによってNULLまたはMinDateに更新されていたことです。

解決策はシンプルで、EntityState.Addedの場合にCreatedDateを設定するだけでよく、SaveChangesオーバーライドで作業を行う前にentity.CreatedDate.IsModified = falseを設定するだけで、Updatesからの変更を無視しました。 CreatedDateを追加すると、数行後に設定されます。

4
Brian Ogden

Code Firstは現在、列のデフォルト値を提供するメカニズムを提供していません。

CreatedDateを自動更新するには、基本クラスを手動で変更または作成する必要があります

public abstract class MyBaseClass
{
    public MyBaseClass()
    {
        CreatedDate = DateTime.Now;
    }
    public Datetime CreatedDate { get; set; }
}
2
Aiska Hendra

EF Coreの場合、MSが推奨する解決策は デフォルト値 にあります。

DBContextでFluent APIを使用します。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}
1
Laobu