![](/img/trans.png)
[英]Entity Types Cannot Share the same table (EF6) (One to Many Relationship)
[英]EF6: “entity types cannot share table” error without any table splitting
我創建了一個 EntityFramework 6 數據上下文(代碼優先)來表示數據庫中的一些表:至於下面引用的重現代碼,一個( Items
)包含某種字典的項目,另一個( Notes
)包含一些可以附在物品上。 一個項目可以包含 0 個或多個注釋。 這里沒有什么困難:我將為每個表只有 1 個 POCO 對象,這就是我正在做的; 然而,當從我的DbContext
初始化數據庫時,我收到錯誤:
"The entity types 'EfItem' and 'Item' cannot share table 'Item' because they are not in the same type hierarchy or do not have a valid one to one foreign key relationship with matching primary keys between them."
現在,對於將多個對象映射到同一個 SQL 表的情況,此錯誤似乎很有意義,但這里的情況並非如此。 對於每個表,我只有 1 個且只有 1 個具體對象。 那么,這個錯誤的原因可能是什么?
我創建了一個重現解決方案,您可以從https://1drv.ms/u/s!AMHCfliT740PkK9H下載,需要進一步解釋。
這個解決方案的要點是,我需要讓客戶端代碼完全不知道所選擇的存儲技術,可能是 RDBMS、NoSql DB 等。為此,在我的解決方案中,我有一個“核心”項目,一個 PCL,它包含只處理接口的高級存儲庫的接口。 例如,我有像AddItem(IItem item)
這樣的方法,而不是直接使用具體類型。
這允許我根據所選技術的要求自定義具體對象:例如,EF 對象需要“父”導航屬性,而這些在 MongoDB 中沒有意義。 當然,這種方法的缺點是必須重新定義大多數具體類型,並將它們轉換為它們的接口實現對應物:例如,在 EF 中,我有一個EfItem
對象,它可以轉換為IItem
。 請注意,此對象不實現此接口,但可以簡單地轉換為它:EF 強制我在導航屬性中使用具體類型(參見例如How to use interface properties with CodeFirst ),以便例如項目的Notes
集合的類型為INote
在核心項目中,但在 EF 項目中屬於EfNote
類型。
至於 EF6 項目,我添加了幾個 POCO 對象來表示項目和注釋,以及一個DbContext
派生類,每個類型都有一個DbSet
( EfItem
、 EfNote
)。 請注意,這些對象是簡單的、具體的類型,與任何其他具體類型都沒有直接關系,而且通常它們甚至沒有實現相應的核心接口。 例如,在核心項目中,我有一個Item
具體類型實現IItem
,但它完全獨立於EfItem
( EfItem
有List<EfNote> Notes
而IItem
有List<INote> Notes
)。 沒有繼承,也沒有分表; EfItem
映射到 SQL 表Item
, EfNote
到Note
。
這是我的 EF 對象的基本代碼:
public class EfItem
{
public string Id { get; set; }
public string SortId { get; set; }
public string ParentId { get; set; }
public string Head { get; set; }
public short ElementCode { get; set; }
public int LegacyNumber { get; set; }
public int Flags { get; set; }
public string Lemma { get; set; }
public short Homograph { get; set; }
public string Content { get; set; }
public DateTime TimeCreated { get; set; }
public string CreatorId { get; set; }
public IList<EfNote> Notes { get; set; }
}
public class EfNote
{
public string Id { get; set; }
public string ItemId { get; set; }
public Item Item { get; set; }
public string BookmarkId { get; set; }
public string UserId { get; set; }
public string Text { get; set; }
public byte Level { get; set; }
public DateTime TimeCreated { get; set; }
}
這是我的 EF 上下文:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Conventions.Remove<PluralizingTableNameConvention>();
// item
mb.Entity<EfItem>().ToTable("Item");
mb.Entity<EfItem>().Property(i => i.Id).IsFixedLength().HasMaxLength(32)
.IsRequired().IsUnicode(false);
mb.Entity<EfItem>().Property(i => i.SortId).HasMaxLength(500)
.IsRequired().IsUnicode(false);
mb.Entity<EfItem>().Property(i => i.ParentId).IsFixedLength().HasMaxLength(32)
.IsUnicode(false);
mb.Entity<EfItem>().Property(i => i.Head).HasMaxLength(50).IsUnicode(true);
mb.Entity<EfItem>().Property(i => i.ElementCode).IsRequired();
mb.Entity<EfItem>().Property(i => i.LegacyNumber).IsRequired();
mb.Entity<EfItem>().Property(i => i.Flags).IsRequired();
mb.Entity<EfItem>().Property(i => i.Lemma).HasMaxLength(200).IsRequired();
mb.Entity<EfItem>().Property(i => i.Homograph).IsRequired();
mb.Entity<EfItem>().Property(i => i.Content).IsRequired().IsUnicode(true)
.HasColumnType("xml");
mb.Entity<EfItem>().Property(i => i.TimeCreated)
.IsRequired()
.HasColumnType("datetime2");
mb.Entity<EfItem>().Property(i => i.CreatorId).HasMaxLength(100).IsRequired();
// notes
mb.Entity<EfNote>().ToTable("Note");
mb.Entity<EfNote>().Property(n => n.Id).IsFixedLength().HasMaxLength(32)
.IsRequired().IsUnicode(false);
mb.Entity<EfNote>().Property(n => n.ItemId).IsFixedLength().HasMaxLength(32)
.IsRequired().IsUnicode(false);
mb.Entity<EfNote>().Property(n => n.BookmarkId)
.HasMaxLength(50).IsUnicode(false).IsRequired();
mb.Entity<EfNote>().Property(n => n.UserId).HasMaxLength(100).IsRequired();
mb.Entity<EfNote>().Property(n => n.Text).HasMaxLength(2000).IsRequired();
mb.Entity<EfNote>().Property(n => n.Level).IsRequired();
mb.Entity<EfNote>().Property(n => n.TimeCreated).IsRequired()
.HasColumnType("datetime2");
base.OnModelCreating(mb);
}
SQL 表定義是:
CREATE TABLE [dbo].[Item](
[Id] [char](32) NOT NULL,
[SortId] [varchar](500) NOT NULL,
[ParentId] [char](32) NULL,
[Head] [nvarchar](50) NULL,
[ElementCode] [smallint] NOT NULL,
[LegacyNumber] [int] NOT NULL,
[Flags] [int] NOT NULL,
[Lemma] [nvarchar](200) NOT NULL,
[Homograph] [smallint] NOT NULL,
[Content] [xml] NOT NULL,
[CreatorId] [nvarchar](100) NOT NULL,
[TimeCreated] [datetime2](7) NOT NULL,
CONSTRAINT [PK_Item] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
CREATE TABLE [dbo].[Note](
[Id] [char](32) NOT NULL,
[ItemId] [char](32) NOT NULL,
[BookmarkId] [varchar](50) NOT NULL,
[UserId] [nvarchar](100) NOT NULL,
[Text] [nvarchar](2000) NOT NULL,
[Level] [tinyint] NOT NULL,
[TimeCreated] [datetime2](7) NOT NULL,
CONSTRAINT [PK_Note] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
在您的 WorkContext.cs 中
改變
public DbSet<EfItem> Items { get; set; }
到
public DbSet<EfItem> EFItems { get; set; }
也在方法
protected override void OnModelCreating(DbModelBuilder mb)
b.Entity<EfItem>().ToTable("EFItem");
EF 遵循 C# 類和 DB 表名之間的一些命名約定,因為您創建了一個名為“Item”的類,恐怕 EF 將類 Item 和 EFItem 混合在一起。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.