26

我正在嘗試爲我的模型中的實體添加CreatedDate屬性,並使用EF5 Code First。我希望這個日期不會被更改一次,我希望它是一個UTC日期。我不想使用構造函數,因爲我的模型中有很多實體要從包含CreatedDate屬性的抽象類繼承,並且我無法使用接口實施構造函數。將CreatedDate添加到使用實體框架的實體5代碼優先

我已經嘗試了不同的數據說明,我試圖寫一個數據庫初始化,將拿起一個特定的實體類型和正確的table_namecolumn_name一個getdate()默認值寫入一個ALTER約束,但我一直沒能正確編寫該代碼。

請不要將我引用到AuditDbContext - Entity Framework Auditing ContextEntityFramework.Extended工具,因爲他們不會在這裏做我所需要的。

UPDATE

CreatedDateSaveChanges()空,因爲我傳遞一個ViewModel我的看法,它正確地沒有叫這CreatedDate審計屬性。即使我將模型傳遞給了我的視圖,我也不會在視圖中編輯或存儲CreatedDate

我讀here,我可以添加[DatabaseGenerated(DatabaseGeneratedOption.Identity)],這會告訴EF插入和更新後正確的存儲CreatedDate,但不允許它通過我的應用程序進行更改:但我只是通過增加該屬性得到Cannot insert explicit value for identity column in table when IDENTITY_INSERT is set to OFF錯誤。

我即將切換到EF Model First,因爲在Code First中實現這個簡單的數據庫要求是荒謬的。

回答

65

這是我如何做的:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
public DateTime CreatedDate{ get; set; } 
在我移民的最多

()方法:

AddColumn("Agents", "CreatedDate", n => n.DateTime(nullable: false, defaultValueSql: "GETUTCDATE()")); 
+0

只有在您的課堂上有註釋的情況下,我纔會使用SaveChanges方法回答。 – Maslow

+0

@Rusty Divine:出於某種原因總是將它設置爲01/01/1900 12:00:00 AM –

+4

我找到了一個更好的方法來實現它:https://andy.mehalick.com/2014/02/06/ ef6-added-a-created-datetime-column-automatically-with-code-first-migrations – Dragouf

-1
Accounts account; 
account.Acct_JoinDate = DateTime.Now.ToUniversalTime(); 
data.Accounts.Add(account); 
data.SaveChanges(); 

爲什麼不給模型創建時間戳?類似於這裏的這些帳戶。

+5

我希望審覈功能能夠自動執行並且不在我的控制器中。我不希望其他開發人員每次執行Add時都必須記得輸入CreatedDate。 –

25

覆蓋調用SaveChanges法在上下文:

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(); 

} 

更新,因爲評論:只有新加入的實體將擁有自己的日期定。

+0

令人敬畏的建議,但這個問題的一個問題是,我沒有將CreatedDate傳遞給我的視圖。我傳遞一個ViewModel到我的視圖,然後使用AutoMapper將我的ViewModel中的字段映射到我的視圖,所以CreatedDate在保存時總是爲空,我讀到將[DatabaseGenerated(DatabaseGeneratedOption.Identity)]屬性添加到我的CreatedDate將允許EF從數據庫正確加載數據,在插入或更新soentity之後重新加載數據,在應用程序中最新,同時不允許您更改該值,但這隻會導致錯誤 –

+5

不知道我是否正確理解您。這是傍晚,我可能一直在喝酒 - 對不起。但是,如果CreatedDate對上下文不可用:那麼數據庫觸發器如何呢? (是的,當我提出*觸發*時,確實已經喝酒了) –

+0

我通常會做觸發器,但我正在使用EF5 Code First。我可以通過CodeFirst添加觸發器,但它違背了CodeFirst的主要原則,即將業務規則保留在一個地方。我無法相信沒有辦法可以將實體屬性設置爲「只讀」,這樣,無論是否存在於上下文中,它都不會更新值,除非我明確這樣做。 –

4

好吧,所以這裏的主要問題是,每當我調用SaveChanges時都會更新CreatedDate,並且因爲我沒有將CreatedDate傳遞給我的視圖,所以它被實體框架更新爲NULL或MinDate。

解決辦法很簡單,知道我只需要設置CreatedDate時EntityState.Added,我只是把我的entity.CreatedDate.IsModified =假前做任何工作在我的SaveChanges覆蓋,這樣,我忽略的變化,從更新如果它是一個Add,則CreatedDate會在稍後設置幾行。

-1

Code First目前沒有提供提供列默認值的機制。

您需要手動修改或創建基類來自動更新CreatedDate

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

但是如何更新實體。在構造函數中初始化CreatedDate將覆蓋更新時的原始CreateDate。不是嗎?這讓我瘋狂 –

+1

@Adolfo首先構造函數運行,然後設置本地字段的默認值,並且只有在EF將把db值推入內存中的實體對象之後。因此,對於現有實體,CreatedDate的db值不會被'DateTime.Now'覆蓋。 – Maarten

3

類似於Stephans's Answer但與Reflection和也會忽略所有用戶(外部)更新創建/更新時間。 Show Gist

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