1. 程式人生 > 實用技巧 >3.3 建立模型 陰影屬性

3.3 建立模型 陰影屬性

概念

影子屬性是未在 .NET 實體類中定義但在 EF Core 模型中為該實體型別定義的屬性。 這些屬性的值和狀態純粹在更改跟蹤器中進行維護。 當資料庫中的資料不應在對映的實體型別上公開時,陰影屬性非常有用。

陰影屬性不屬於您的實體類,因此,您無法在訪問實體的其它屬性時訪問它,只能在構建實體資料模型時為實體型別配置陰影屬性,並且他們也將對映到資料庫列,陰影屬性的值和狀態僅在更改追蹤器中維護;

讓我們瞭解shadow屬性的實際方面。假設我們需要維護資料庫表中每個記錄的建立和更新日期。您學習瞭如何通過在實體類中定義CreatedDate和UpdatedDate屬性來設定EF Core中實體的建立和修改日期。在這裡,我們將看到如何通過使用陰影屬性而不在實體類中包含陰影屬性來實現相同的結果。

考慮以下學生實體類。

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
}

上面的Student類不包含CreatedDate和UpdatedDate屬性來維護建立或更新的時間。我們將它們配置為Student實體上的陰影屬性。

1.定義影子屬性

public class SchoolContext : DbContext
{
    public SchoolContext() : base()
    {

    }

    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        modelBuilder.Entity<Student>().Property<DateTime>("CreatedDate");
        modelBuilder.Entity<Student>().Property<DateTime>("UpdatedDate");
    }

    public DbSet<Student> Students { get; set; }
}

如您所見,Property()方法用於配置陰影屬性。將shadow屬性的名稱指定為字串,並將型別指定為通用引數。如果在Property()方法中指定的名稱與現有屬性的名稱匹配,則EF Core將將該現有屬性配置為陰影屬性,而不是引入新的陰影屬性。

2. 資料庫中的陰影屬性

定義陰影屬性後,我們需要更新資料庫架構,因為陰影屬性將對映到相應的資料庫列。
為此,請在Visual Studio的程式包管理器控制檯中使用以下命令新增資料庫遷移。

PM> add-migration addShadowProperty
PM> update-database

現在,Student表將包括兩列,SQL Server中的CreatedDate和UpdatedDate,如下所示。
因此,即使我們沒有在Student類中包含這些屬性並將其配置為陰影屬性,資料庫也將具有相應的列。

3.訪問陰影屬性

using (var context = new SchoolContext())
{
    var std = new Student(){ StudentName = "Bill"  };

    // sets the value to the shadow property
    context.Entry(std).Property("CreatedDate").CurrentValue = DateTime.Now;

    // gets the value of the shadow property
    var createdDate = context.Entry(std).Property("CreatedDate").CurrentValue;
}

但是,在我們的方案中,我們想在SaveChanges()方法上自動將值設定為這些陰影屬性,這樣就不必在每個實體物件上手動設定它們。因此,請在上下文類中重寫SaveChanges()方法,如下所示。

public override int SaveChanges()
{
    var entries = ChangeTracker
        .Entries()
        .Where(e =>
                e.State == EntityState.Added
                || e.State == EntityState.Modified);

    foreach (var entityEntry in entries)
    {
        entityEntry.Property("UpdatedDate").CurrentValue = DateTime.Now;

        if (entityEntry.State == EntityState.Added)
        {
            entityEntry.Property("CreatedDate").CurrentValue = DateTime.Now;
        }
    }

    return base.SaveChanges();
}

這將自動將值設定為CreatedDate和UpdatedDate陰影屬性。
現在,執行以下程式碼並檢查資料庫中的記錄。

using (var context = new SchoolContext())
{
    var std = new Student(){ StudentName = "Bill"  };
    context.Add(std);
    context.SaveChanges();
}

上面的程式碼將在Student表中插入帶有CreatedDate和UpdatedDate的以下記錄。

因此,通過配置陰影屬性,我們不必將它們包括在實體類中。

在所有實體上配置陰影屬性

您可以一次在所有實體上配置陰影屬性,而不是為所有實體手動配置它們。
例如,我們可以一次在所有實體上配置CreatedDate和UpdatedDate,如下所示。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var allEntities = modelBuilder.Model.GetEntityTypes();

    foreach (var entity in allEntities)
    {
        entity.AddProperty("CreatedDate",typeof(DateTime));
        entity.AddProperty("UpdatedDate",typeof(DateTime));
    }
}

何時使用陰影屬性

陰影屬性可以在兩種情況下使用:

  1. 當您不想在對映的實體上公開資料庫列時,例如上面討論的方案。
  2. 當您不想公開外來鍵屬性而只想使用導航屬性來管理關係時。外來鍵屬性將是shadow屬性並對映到資料庫列,但不會作為實體的屬性公開。 (在EF Core中,如果您未在實體類中定義外來鍵屬性,則它將自動為此生成陰影屬性。您無需手動配置外來鍵屬性。)

瞭解如何在執行時檢查陰影屬性

https://www.entityframeworktutorial.net/faq/how-to-check-shadow-property-at-runtime.aspx

應用

  • 審計功能
    目前為止審計 怎麼跟使用者關聯的沒有看到;那幾個審計欄位是知道的;
  • 維護資料庫表中每個記錄的建立和更新日期