簡體   English   中英

如何在實體框架中映射類型為“字典”的屬性?

[英]How do I map property with of type 'Dictionary' with Entity Framework?

using Microsoft.EntityFrameworkCore;

namespace NameSpaceName
{
    public class WordContext : DbContext
    {
        public DbSet<VmWord> Words { get; set; }
        public DbSet<VmWordLocalization> WordLocalization { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlite("Data Source=NameSpaceName.db");
        }
    }
}

namespace NameSpaceName
{
    public class VmWord
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Dictionary<string, VmWordLocalization> Localization { get; set; }
    }
}

namespace NameSpaceName
{
    public class VmWordLocalization
    {
        public int Id { get; set; }
        public string En { get; set; }
        public string Pl { get; set; }
    }
}

我有VmWord表,我需要添加VmWordLocalization作為字典,以便能夠通過鍵獲取本地化變量值;

當我嘗試執行時:

dotnet ef遷移添加Add_Localization_Table --context WordContext

我得到:

無法映射屬性“ VmWord.Localization”,因為它的類型為“字典”,不是受支持的原始類型或有效的實體類型。 顯式映射此屬性,或使用'[NotMapped]'屬性或'OnModelCreating'中的'EntityTypeBuilder.Ignore'忽略它。

如何映射“字典”類型的屬性?

EF中可能沒有Dictionary屬性。 解決方案是用ICollection替換Dictionary

namespace NameSpaceName
{
    public class VmWord
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public ICollection<VmWordLocalization> Localizations { get; set; }
    }

    public class VmWordLocalization
    {
        public int Id { get; set; }

        public string Key { get; set; }  // key from your previous dictionary

        public string En { get; set; }

        public string Pl { get; set; }
    }
}

問題是,字典是什么?如何看待與物理數據庫表的映射(您要查找的是一個包含單詞列表的表,然后是另一個包含單詞列表的表,每次翻譯重復一次)? 我在這里是“吐口水”,因為我不確定您要實現的目標是什么,但是您可能希望僅擁有一個包含單詞ID和語言ID的表格,而不是使用帶有翻譯鏈接的基本單詞它組成了一個復合主鍵,那么您只需應用wordid = x和language = y的位置即可獲得該單詞的正確版本。 或者,如果您在結構上進行了設置,則需要使用外鍵實現子表,並在VmWord類上對其進行定義,如下所示:

public List<VmWordLocalisation> {get;set;}

然后在子表上您將定義外鍵,如下所示

[ForeignKey("Id")]
public VmWord Parent {get;set;}

您還需要在子表上設置一個復合主鍵,以標識ID和語言

希望這可以幫助!

您想要一個具有Dictionary屬性的對象的原因是因為您想要快速查找: Give me the VmWord with the Localization with this Key 換句話說:給定一個鍵,您需要快速查找包含該鍵的VnWordLocalization對象。

在實體框架中, DbSet<...>表示關系數據庫中的表。 關系數據庫不了解Dictionary的概念。

幸運的是,數據庫知道使用鍵進行快速查找的概念。 通常,這是主鍵,但是您可以添加其他可用作鍵的索引。

las,您忘了告訴我們您要使用哪個字符串作為VmWordLocalizations快速查找。 En嗎? 還是Pl 還是一個全新的鑰匙?

如果它是一個全新的Key,那么顯然每個VmWordLocalication都有一個屬性,讓我們將其命名為Key ,它與外鍵VmWordId結合在一起是唯一的。 如果是EnPl ,請將其用作密鑰。

class VmWord
{
    public int Id { get; set; }

    // every VmWord has zero or more Localizations (one-to-many)
    public virtual ICollection<VmWordLocalization> VmWordLocalizations { get; set; }

    ... // other properties
}

class VmWordLocalization
{
    public int Id { get; set; }

    // every VmWordLocalization belongs to exactly one VmWord using foreign key
    public int VmWordId {get; set;}
    public virtual VmWord VmWord {get; set;}

    // every VmWordLocalization has a property Key, which is unique in combination
    // with VmWordId
    public string Key {get; set;}
}

注意:如果Key是整體唯一的,請考慮將其用作主鍵。

注意2:在實體框架中,非虛擬屬性表示表中的列,表之間的關系由虛擬屬性表示

注意3:請考慮遵守實體框架的代碼優先約定。 它消除了對屬性或流暢的API的需求。 僅當您有充分理由時才偏離這些約定。 不必鍵入更少的字符不是一個很好的理由。

如果Key不能作為您的主鍵,則必須添加一個額外的快速查找:索引。 這是在DbContext.OnModelCreating完成的

protected overrid void OnModelCreating(...)
{
     // Every VmWordLocalization has a property Key, which is unique per VmWordId
     // create an index with (VmWordId, Key) as index key
     var vmWordLocalizationEntity = modelBuilder.Entity<VmWordLocalization>();

     // first index annotation: VmWordId:
     vmWordLocalizationEntity.Property(entity => entity.VmWordId)
         .IsRequired()
         .HasColumnAnnotatin(IndexAnnotation.AnnotationName, 
              new IndexAnnotation(new IndexAttribute("index_VmWordId", 0)));

     // 2nd index annotation: Key:
     vmWordLocalizationEntity.Property(entity => entity.Key)
         .IsRequired()
         .HasColumnAnnotatin(IndexAnnotation.AnnotationName, 
              new IndexAnnotation(new IndexAttribute("index_Key", 1)));
}

標識符index_VmWordindex_Key可以是任何東西。 它們只是用於命名索引列的標識符。

數字0和1給出索引的排序順序:首先通過index_VmWordId然后通過index_Key

現在,如果你有一個VmWordId == 10,也可以添加VmWordLocationVmWordId == 10和Key ==“你好”。 但是,如果您嘗試使用這些值添加第二個VmWordLocation ,則會出現異常,就像將兩個具有相同鍵的對象添加到字典中一樣。

現在,在字典中獲取所請求的VmWords及其本地化信息:

var vmWordsWithLocalizations = myDbContext.VmWords.Select(vmWord => new
{
      // select only the properties you plan to use:
      Id = vmWord.Id,
      Name = vmWord.Name,

      Localizations.VmWord.VmwordLocalizations
          .Where(vmWordLocalization => ...) // only if you do't want all vmWordLocalizations
          .ToDictionary(vmWordLocalization => vmWordLocalization.Key,  // Dictionary Key
              new                                                      // Dictionary value
              {   // again: select only the properties you plan to use
                  Id = vmWordLocalization.Id,
                  En = vmWordLocalization.Em,
                  Pl = vmWordLocalization.Pl,

                  // no need: you know it equals vmWord.Id
                  // VmWordId = vmWordLocalization.VmWordId

              }),

});

如果您必須經常執行此操作,請考慮創建擴展功能:

IEnumerable<VmWordWithDictionary> ToVmWordWithDictionary(this IQueryable<VmWord> vmWords)
{
     return vmWords.Select(vmWord => new VmWordEx()
     {
         Id = vmWord.Id,
         Name = vmWord.Name,
         Localizations = vmWord.VmWordLocalizatons
             .Where(vmWordLocalization => ...)
             .ToDictionary(
                 vmWordLocalization => vmWordLocalization.Key        // Key
                 vmWordLocalization => new VmWordLocalizationEx()    // Value
                 {
                      Id = vmWordLocalization.Id,
                      En = vmWordLocalization.Em,
                      Pl = vmWordLocalization.Pl,
                 }),
});

注意:出於效率的考慮,我不想傳輸更多的數據,因此我創建了兩個額外的類,僅包含我需要的數據。

注意:由於字典的原因,返回必須是IEnumerable。 之后,您將無法再執行IQueryable LINQ語句

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM