EF核心計算屬性標記為只讀

c# entity-framework entity-framework-core

背景:每當添加或更新“Item”實體時,我都會覆蓋SaveChanges()方法以自動生成LastUpdatedDate。

Item.cs

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

的DbContext

  protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      ...
      // generated value
      modelBuilder.Entity<Item>()
                  .Property(b => b.LastUpdated)
                  .ValueGeneratedOnAddOrUpdate();

     }

    public override int SaveChanges()
    {
        var now = DateTime.UtcNow;

        foreach (var item in ChangeTracker.Entries<Item>()
            .Where(e => e.State == EntityState.Added || e.State == EntityState.Modified))
        {
            item.Property("LastUpdated").CurrentValue = now;             
        }           

        return base.SaveChanges();
    } 

我遇到的問題是每當調用SaveChanges()時我得到這個異常:

EntityFramework.Core.dll中出現“System.InvalidOperationException”類型的異常,但未在用戶代碼中處理。
附加信息:實體類型“Item”上的屬性“LastUpdated”在保存後被定義為只讀,但其值已被修改或標記為已修改。

要解決這個問題,我必須將IsReadOnlyBeforeSave和IsReadOnlyAfterSave設置為false,如下所示:

        modelBuilder.Entity<Tray>()
            .Property(b => b.LastUpdated)
            .ValueGeneratedOnAddOrUpdate()
            .Metadata.IsReadOnlyBeforeSave = false; 
        modelBuilder.Entity<Tray>()
            .Property(b => b.LastUpdated)
            .Metadata.IsReadOnlyAfterSave = false;

題:

這是在EF Core中設置計算屬性的正確方法嗎?

另外,我可以防止LastUpdated首先被定義為“只讀”嗎?

一般承認的答案

這是在EF Core中設置計算屬性的正確方法嗎?

文檔非常清楚:

添加或更新時生成的值意味著每次保存記錄(插入或更新)時都會生成新值。

警告

如何為添加和更新的實體生成值取決於所使用的數據庫提供程序。 (...)如果指定在添加或更新時生成DateTime屬性,則必須設置生成值的方法(例如數據庫觸發器)。

註釋的名稱 - “DatabaseGeneratedOption” - 可能已經揭示了這些內容。

因此,如果要使用此模式,則應在數據庫中設置觸發器,以在插入和每次更新時設置字段值。通過使用註釋[DatabaseGenerated] 流暢的API .ValueGeneratedOnAddOrUpdate() (不需要同時執行這兩個操作),EF表示它應該在保存更改後從數據庫中讀取值。

至於IsReadOnlyBeforeSave屬性。到目前為止,唯一的文檔是EF源代碼中屬性的XML文檔:

獲取或設置一個值,該值指示在將實體保存到數據庫之前是否可以修改此屬性。如果為true,則在此屬性處於“已Added狀態時為其分配值時,將引發異常。

據我所知,您可能希望將此值設置為true以消除設置此屬性有用的任何期望(因為它不是)。同樣,您可以設置IsReadOnlyAfterSave在現有(未Added )實體中設置屬性時拋出異常。

如果您不想要數據庫生成的值,則可以刪除註釋並像現在一樣分配值。


熱門答案

IsReadOnlyAfterSave標誌已被廢棄,並被AfterSaveBehavior取代。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Device>()
        .Property<string>("TenantId")
        .HasField("_tenantId")
        //.Metadata.IsReadOnlyAfterSave = true;
        .Metadata.AfterSaveBehavior = Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Ignore;
}


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因