繁体   English   中英

EF6:“实体类型不能共享表”错误,没有任何表拆分

[英]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派生类,每个类型都有一个DbSetEfItemEfNote )。 请注意,这些对象是简单的、具体的类型,与任何其他具体类型都没有直接关系,而且通常它们甚至没有实现相应的核心接口。 例如,在核心项目中,我有一个Item具体类型实现IItem ,但它完全独立于EfItemEfItemList<EfNote> NotesIItemList<INote> Notes )。 没有继承,也没有分表; EfItem映射到 SQL 表ItemEfNoteNote

这是我的 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM