简体   繁体   English

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

[英]EF6: “entity types cannot share table” error without any table splitting

I have created an EntityFramework 6 data context (code first) to represent some tables in a database: as for the repro code quoted below, one ( Items ) contains the items of some kind of dictionary, another ( Notes ) contains some notes which can be attached to items.我创建了一个 EntityFramework 6 数据上下文(代码优先)来表示数据库中的一些表:至于下面引用的重现代码,一个( Items )包含某种字典的项目,另一个( Notes )包含一些可以附在物品上。 An item can contain 0 or more notes.一个项目可以包含 0 个或多个注释。 Nothing difficult here: I'll just have 1 POCO object for each table, and this is what I'm doing;这里没有什么困难:我将为每个表只有 1 个 POCO 对象,这就是我正在做的; yet, when initializing the database from my DbContext I get the error:然而,当从我的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."

Now, this error seems to be meaningful for cases where several objects are mapped to the same SQL table, but this is not the case here.现在,对于将多个对象映射到同一个 SQL 表的情况,此错误似乎很有意义,但这里的情况并非如此。 I have 1 and only 1 concrete object for each of the tables.对于每个表,我只有 1 个且只有 1 个具体对象。 So, what could be the reason of this error?那么,这个错误的原因可能是什么?

I have created a repro solution you can download from https://1drv.ms/u/s!AMHCfliT740PkK9H , which needs further explanation.我创建了一个重现解决方案,您可以从https://1drv.ms/u/s!AMHCfliT740PkK9H下载,需要进一步解释。

The main point in this solution is that I need to keep the client code totally agnostic of the storage technology of choice, which might be a RDBMS, a NoSql DB, etc. To this end, in my solution I have a "core" project, a PCL, which contains the interface for a high-level repository dealing only with interfaces.这个解决方案的要点是,我需要让客户端代码完全不知道所选择的存储技术,可能是 RDBMS、NoSql DB 等。为此,在我的解决方案中,我有一个“核心”项目,一个 PCL,它包含只处理接口的高级存储库的接口。 For instance, I have methods like AddItem(IItem item) , rather than directly using a concrete type.例如,我有像AddItem(IItem item)这样的方法,而不是直接使用具体类型。

This allows me to customize the concrete objects as required by the technology of choice: for instance, EF objects require "parent" navigation properties, while these would not make sense in MongoDB.这允许我根据所选技术的要求自定义具体对象:例如,EF 对象需要“父”导航属性,而这些在 MongoDB 中没有意义。 Of course, the downside of this approach is having to redefine most of the concrete types, and converting them into their interface-implementing counterparts: for instance, in EF I have an EfItem object, which can be converted into IItem .当然,这种方法的缺点是必须重新定义大多数具体类型,并将它们转换为它们的接口实现对应物:例如,在 EF 中,我有一个EfItem对象,它可以转换为IItem Note that this object does not implement this interface, but is simply convertible to it: EF forces me to use concrete types in navigation properties (see eg How to use interface properties with CodeFirst ), so that eg the item's Notes collection is of type INote in the core project, but of type EfNote in the EF project.请注意,此对象不实现此接口,但可以简单地转换为它:EF 强制我在导航属性中使用具体类型(参见例如How to use interface properties with CodeFirst ),以便例如项目的Notes集合的类型为INote在核心项目中,但在 EF 项目中属于EfNote类型。

As for the EF6 project, I have added a couple of POCO objects to represent items and notes, and a DbContext derived class with a DbSet for each type ( EfItem , EfNote ).至于 EF6 项目,我添加了几个 POCO 对象来表示项目和注释,以及一个DbContext派生类,每个类型都有一个DbSetEfItemEfNote )。 Note that these objects are plain, concrete types with no direct relationship to either any other concrete type, and often they are not even implementing the corresponding core interface.请注意,这些对象是简单的、具体的类型,与任何其他具体类型都没有直接关系,而且通常它们甚至没有实现相应的核心接口。 For instance, in the core project I have an Item concrete type implementing IItem , but it's completely independent from EfItem ( EfItem has List<EfNote> Notes while IItem has List<INote> Notes ).例如,在核心项目中,我有一个Item具体类型实现IItem ,但它完全独立于EfItemEfItemList<EfNote> NotesIItemList<INote> Notes )。 There is no inheritance, and no table splitting;没有继承,也没有分表; EfItem is mapped to SQL table Item , and EfNote to Note . EfItem映射到 SQL 表ItemEfNoteNote

Here is the essential code for my EF objects:这是我的 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; }
}

Here is my EF context:这是我的 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);
}

The SQL tables definitions are: 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
)

In your WorkContext.cs在您的 WorkContext.cs 中

Change改变

public DbSet<EfItem> Items { get; set; }

to

public DbSet<EfItem> EFItems { get; set; }

Also in method也在方法

protected override void OnModelCreating(DbModelBuilder mb)

b.Entity<EfItem>().ToTable("EFItem");

EF follows some naming convention between C# class and DB table name, since you have created a class named 'Item', i am afraid EF mixed class Item and EFItem together. EF 遵循 C# 类和 DB 表名之间的一些命名约定,因为您创建了一个名为“Item”的类,恐怕 EF 将类 Item 和 EFItem 混合在一起。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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