![](/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.