モデルのエンティティにCreatedDate
プロパティを追加しようとしていますが、EF5 Code Firstを使用しています。この日付は一度設定すると変更されず、UTC日付になります。モデルにはCreatedDate
プロパティを含む抽象クラスから継承したい多くのエンティティがあるため、コンストラクターを使用したくありません。また、インターフェイスでコンストラクターを強制することはできません。
さまざまなデータアノテーションを試し、特定のエンティティタイプを選択し、正しいtable_name
およびcolumn_name
のgetdate()
デフォルト値を使用して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に切り替えようとしています。
ここに私がそれをした方法があります:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedDate{ get; set; }
私の移行のUp()メソッドで:
AddColumn("Agents", "CreatedDate", n => n.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()"));
コンテキストで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();
}
コメントのため更新:新しく追加されたエンティティのみに日付が設定されます。
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();
}
ここでの主要な問題は、SaveChangesを呼び出すたびにCreatedDateが更新され、CreatedDateをビューに渡さなかったため、Entity FrameworkによってNULLまたはMinDateに更新されていたことです。
解決策はシンプルで、EntityState.Addedの場合にCreatedDateを設定するだけでよく、SaveChangesオーバーライドで作業を行う前にentity.CreatedDate.IsModified = falseを設定するだけで、Updatesからの変更を無視しました。 CreatedDateを追加すると、数行後に設定されます。
Code Firstは現在、列のデフォルト値を提供するメカニズムを提供していません。
CreatedDateを自動更新するには、基本クラスを手動で変更または作成する必要があります
public abstract class MyBaseClass
{
public MyBaseClass()
{
CreatedDate = DateTime.Now;
}
public Datetime CreatedDate { get; set; }
}
EF Coreの場合、MSが推奨する解決策は デフォルト値 にあります。
DBContextでFluent APIを使用します。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
}