EF6 中使用复合键的每个具体类型 (TPC) 映射表

Posted

技术标签:

【中文标题】EF6 中使用复合键的每个具体类型 (TPC) 映射表【英文标题】:Table per Concrete Type(TPC) mapping with Composite key in the EF6 【发布时间】:2017-04-07 05:10:36 【问题描述】:

我有一个表层次结构,其中包含每个具体类型 (TPC) 映射的表。 (我不确定 [Key, Column] 属性是否必要,但根据https://***.com/a/19792915/959779 它应该可以工作)

类结构:

public abstract class BaseEntity

    [Key, Column(Order = 0)]
    public int Id  get; set; 

public class Page: BaseEntity 
    string Data  get; set; 

public class PageBackup: Page 
    [Key, Column(Order = 1)]
    public int PageId  get; set; 
    public virtual Page Page  get; set; 

PagePageBackup 实体的Id 相交时(在向表中添加一些项目后)EF 抛出下一个执行

“EntitySet 'EUICDataContext.Pages' 中的所有对象都必须具有唯一的主键。 但是,“Entities.PageBackup”类型的实例和类型的实例 'Entities.Page' 都具有相同的主键值,'EntitySet=Pages;Id=6'。 "

实体映射代码如下:

class PageMapping : EntityTypeConfiguration<Page> 

    public PageMapping ()
    
        Map(m => m.ToTable("Page"); );
        HasKey(t => t.Id );
    


class PageBackupMapping : EntityTypeConfiguration<PageBackup> 

    public PageBackupMapping ()
    
        Map(m =>
            m.MapInheritedProperties();
            m.ToTable("PageBackup");
        );
        HasKey(t => new  t.Id, t.PageId );
    
 

问题是虽然在 EF PageMapping 有复合键 Update-Database 种子脚本创建具有下一个签名的表:

CREATE TABLE [dbo].[PageBackup](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [PageId] [int] NOT NULL,
    [Data] [nvarchar](max) NULL,
    CONSTRAINT [PK_dbo.PageBackup] PRIMARY KEY CLUSTERED 
    (
            [Id] ASC
    )

EF 是否允许使用复合键创建表(有很多映射示例,但我没有找到任何关于迁移的信息)?

以及如何代表TPC映射来描述这样的配置?

任何其他解决方案建议都会有所帮助。

【问题讨论】:

【参考方案1】:

我正在玩它,看来 EF 6 不支持这种情况。我的迁移使用 Id 主键自动生成。

  CreateTable(
            "dbo.PageBackUp",
            c => new
                
                    Id = c.Int(nullable: false),
                    PageId = c.Int(nullable: false),
                )
            .PrimaryKey(t => t.Id);

之后,我尝试在 EF Core 1.1.0 上管理这个。在那种情况下我遇到了错误

无法在“页面”上配置键,因为它是派生类型。这 必须在根类型“BaseEntity”上配置密钥。如果你没有 打算将“BaseEntity”包含在模型中,确保它是 未包含在上下文的 DbSet 属性中,在 对 ModelBuilder 的配置调用,或从导航中引用 模型中包含的类型的属性。

我认为这是实体框架的限制。您可以通过此问题向EF repo 提出问题。

我的 EF Core 配置是:

public class ProductContext : DbContext

    public ProductContext()
    

    
    public ProductContext(DbContextOptions<ProductContext> options)
        : base(options)
     

    public DbSet<Page> Page  get; set; 
    public DbSet<PageBackup> PageBackup  get; set; 

    protected override void OnConfiguring(DbContextOptionsBuilder builder)
    
        builder.UseSqlServer("Data Source=.\\sqlexpress;");
        base.OnConfiguring(builder);
    

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    
        modelBuilder.Entity<Page>()
            .HasBaseType<BaseEntity>()
            .ToTable("Page")
            .HasKey(t => t.Id);

        modelBuilder.Entity<PageBackup>()
            .HasBaseType<Page>()
            .HasKey(t => new  t.PageId, t.Id );

        base.OnModelCreating(modelBuilder);
    

EF 6 版本:

public class ProductContext : DbContext

    public DbSet<Page> Page  get; set; 
    public DbSet<PageBackup> PageBackup  get; set; 


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        modelBuilder.Entity<Page>()
            .Map(m => m.MapInheritedProperties().ToTable("Page"))
            .HasKey(t => t.Id);


        modelBuilder.Entity<PageBackup>()
            .Map(m => m.MapInheritedProperties().ToTable("PageBackUp"))
            .HasKey(t => new  t.PageId, t.Id );

        base.OnModelCreating(modelBuilder);
    

【讨论】:

以上是关于EF6 中使用复合键的每个具体类型 (TPC) 映射表的主要内容,如果未能解决你的问题,请参考以下文章

带有 EF 和自动映射器的 OData:无法比较..'。仅支持原始类型、枚举类型和实体类型

用于更改表添加复合主键的批量 SQL 语句

Laravel 与复合外键的关系

在 SqlServer 提供程序清单中找不到存储类型“Varchar(100)”

如何进行 Hibernate XML 映射,一对多使用 1 PK 映射到另一个具有复合键的实体

使用复合/复合主键的缺点是啥?