EF Core 索引器屬性(Indexer property)場景及應用

雨太阳發表於2024-08-12

EF Core 索引器屬性(Indexer property)場景及應用

簡介

EF Core 中的索引器屬性(Indexer Property)是指透過一個特殊的屬性來訪問實體類中的資料,而不必明確宣告實體屬性。這種屬性在一些動態或未預定義的場景中非常有用,比如當實體的屬性名在編譯時並不確定,或者屬性名集合較大時。

場景及應用

1.動態屬性訪問
索引器屬性最常見的應用場景是動態屬性訪問。這在處理 JSON 資料或其他半結構化資料時尤其有用。例如,當你有一個屬性名稱集合在編譯時並不確定,或者從外部源(如配置檔案、API 響應等)中獲取屬性名時,可以使用索引器屬性來動態訪問這些屬性。

2.字典資料結構
如果實體類包含一個字典型別的屬性,可以透過索引器屬性來訪問字典中的資料。例如,如果你的實體中包含了一個 Dictionary<string, object> 來儲存額外的資料,使用索引器屬性可以簡化訪問這些資料的方式。

public class DynamicEntity
{
    private Dictionary<string, object> _additionalData = new Dictionary<string, object>();

    public object this[string key]
    {
        get => _additionalData.ContainsKey(key) ? _additionalData[key] : null;
        set => _additionalData[key] = value;
    }
}

3.後設資料處理
在一些應用場景中,需要將不同的後設資料儲存在實體中而不增加額外的列。在這種情況下,可以使用索引器屬性來處理這些後設資料。例如,當你需要根據業務邏輯在資料庫表中儲存額外的、可變的屬性集合時,可以使用索引器屬性來管理這些屬性。

4.簡化程式碼
索引器屬性可以簡化程式碼,減少顯式宣告屬性的需求。在開發過程中,減少了重複程式碼,提高了程式碼的可維護性和靈活性。

EF Core 配置

在 EF Core 中使用索引器屬性時,需要在模型配置階段進行一些特殊的配置,以確保 EF Core 正確地將索引器屬性對映到資料庫欄位。這裡我們討論幾種常見的配置方法。

1. 使用 Dictionary<string, object> 的索引器屬性

如果你在實體類中使用了 Dictionary<string, object> 作為索引器屬性的儲存機制,並希望 EF Core 將這些鍵值對儲存在資料庫表的專用列中,可以按照以下方式配置:

實體類示例

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }

    private Dictionary<string, object> _extendedProperties = new Dictionary<string, object>();

    public object this[string key]
    {
        get => _extendedProperties.ContainsKey(key) ? _extendedProperties[key] : null;
        set => _extendedProperties[key] = value;
    }
}

OnModelCreating 方法中配置

DbContext 中的 OnModelCreating 方法中配置索引器屬性。你可以使用 OwnsMany 來配置字典的對映。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>()
        .OwnsMany(p => p._extendedProperties, a =>
        {
            a.Property<string>("Key");
            a.Property<string>("Value");
            a.WithOwner().HasForeignKey("ProductId");
            a.ToTable("ProductExtendedProperties");
        });
}

此配置將 Product 實體的擴充套件屬性儲存在一個單獨的表 ProductExtendedProperties 中,該表將有三列:ProductIdKeyValue

2. 直接將索引器屬性對映到表的列

如果你希望直接將索引器屬性對映到表的列(而不是將字典儲存在單獨的表中),你可以使用 Property 方法來配置。

實體類示例

public class MultilingualContent
{
    private Dictionary<string, string> _translations = new Dictionary<string, string>();

    public int Id { get; set; }

    public string this[string language]
    {
        get => _translations.ContainsKey(language) ? _translations[language] : null;
        set => _translations[language] = value;
    }
}

OnModelCreating 方法中配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MultilingualContent>()
        .Property(e => e["en"])
        .HasColumnName("EnglishContent");

    modelBuilder.Entity<MultilingualContent>()
        .Property(e => e["fr"])
        .HasColumnName("FrenchContent");
}

這種配置將索引器屬性中不同語言的內容直接對映到 MultilingualContent 表中的不同列(如 EnglishContentFrenchContent)。

3. 對映到 JSON 列

EF Core 5.0 開始支援將複雜型別對映到 JSON 列中。如果你使用索引器屬性儲存複雜物件,可以將其對映為 JSON。

實體類示例

public class Configuration
{
    private Dictionary<string, string> _settings = new Dictionary<string, string>();

    public int Id { get; set; }

    public string this[string key]
    {
        get => _settings.ContainsKey(key) ? _settings[key] : null;
        set => _settings[key] = value;
    }
}

OnModelCreating 方法中配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Configuration>()
        .Property(e => e._settings)
        .HasColumnType("jsonb")
        .HasColumnName("Settings");
}

這種配置將整個字典對映為一個 JSON 欄位,可以靈活儲存複雜和動態的資料結構。

完整例項之-多語言支援

在處理多語言支援的案例中,配置好 EF Core 後,你可以透過索引器屬性動態地訪問和更新不同語言的內容。下面將詳細說明如何呼叫和請求使用這個多語言支援的模型。

1. 設定資料庫上下文和實體

首先,假設你已經按照前面的指導配置好了 MultilingualContent 實體和資料庫上下文。這裡是完整的實體類和上下文的程式碼:

實體類 MultilingualContent

public class MultilingualContent
{
    private Dictionary<string, string> _translations = new Dictionary<string, string>();

    public int Id { get; set; }

    public string this[string language]
    {
        get => _translations.ContainsKey(language) ? _translations[language] : null;
        set => _translations[language] = value;
    }
}

資料庫上下文 AppDbContext

public class AppDbContext : DbContext
{
    public DbSet<MultilingualContent> MultilingualContents { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MultilingualContent>()
            .Property(e => e["en"])
            .HasColumnName("EnglishContent");

        modelBuilder.Entity<MultilingualContent>()
            .Property(e => e["fr"])
            .HasColumnName("FrenchContent");

        // 配置其他語言...
    }
}

2. 新增資料

假設你需要為一段內容新增英語和法語版本。你可以使用索引器屬性來設定這些語言的內容。

using (var context = new AppDbContext())
{
    var content = new MultilingualContent();
    content["en"] = "Hello, world!";
    content["fr"] = "Bonjour, le monde!";

    context.MultilingualContents.Add(content);
    context.SaveChanges();
}

上面的程式碼會在資料庫中插入一條記錄,其中包含英語和法語的文字。

3. 檢索資料

假設你想要根據語言檢索某段內容。可以使用索引器屬性來獲取相應語言的文字。

using (var context = new AppDbContext())
{
    var content = context.MultilingualContents.FirstOrDefault(c => c.Id == 1);

    if (content != null)
    {
        string englishText = content["en"];
        string frenchText = content["fr"];

        Console.WriteLine($"English: {englishText}");
        Console.WriteLine($"French: {frenchText}");
    }
}

這段程式碼會從資料庫中檢索 ID 為 1 的內容,並輸出其英語和法語版本。

4. 更新資料

你可以使用索引器屬性來更新某個語言的內容。

using (var context = new AppDbContext())
{
    var content = context.MultilingualContents.FirstOrDefault(c => c.Id == 1);

    if (content != null)
    {
        content["en"] = "Hello, everyone!";
        content["fr"] = "Bonjour, tout le monde!";

        context.SaveChanges();
    }
}

這段程式碼會更新 ID 為 1 的內容,將英語和法語文字分別更新為新的內容。

5. 刪除資料

刪除操作和普通的實體一樣,可以使用 EF Core 提供的標準方法。

using (var context = new AppDbContext())
{
    var content = context.MultilingualContents.FirstOrDefault(c => c.Id == 1);

    if (content != null)
    {
        context.MultilingualContents.Remove(content);
        context.SaveChanges();
    }
}

這段程式碼會從資料庫中刪除 ID 為 1 的內容及其所有語言版本的文字。

總結

EF Core 的索引器屬性對於處理動態屬性、後設資料、或結構化但不固定的屬性集合非常有用。它能夠提高程式碼的靈活性和可維護性,特別是在處理需要儲存可變屬性的場景時。

END 歡迎關注 "ShareFlow" 公眾號

相關文章