0

I have an table hierarchy with Table per Concrete Type (TPC) mapping. (I not sure that [Key, Column] attribute are necessary but according https://stackoverflow.com/a/19792915/959779 it's should work)

Class structure:

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; }
}

WhenId of the Page and PageBackup entities are intersect(after adding to tables some items) EF throw the next excution

"All objects in the EntitySet 'EUICDataContext.Pages' must have unique primary keys. However, an instance of type 'Entities.PageBackup' and an instance of type 'Entities.Page' both have the same primary key value, 'EntitySet=Pages;Id=6'. "

Entities mapping code below:

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 });
    }
 }

The problem is although in the EF PageMapping has composite key Update-Database seed script creates table with the next signature:

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
    )

Is EF allows to create tables with composite keys(lot of examples with mapping but I didn't found any about the migrations)?

And how to describe such configuration on behalf of TPC mapping?

Any other solution proposal will be helpful.

Community
  • 1
  • 1
Stadub Dima
  • 858
  • 10
  • 24

1 Answers1

1

I'm playing with it, it looks like this is case is not supported by the EF 6. My migration automatically generated with Id primary key.

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

After that I've try to manage this one on EF Core 1.1.0 . I got an error in that case

A key cannot be configured on 'Page' because it is a derived type. The key must be configured on the root type 'BaseEntity'. If you did not intend for 'BaseEntity' to be included in the model, ensure that it is not included in a DbSet property on your context, referenced in a configuration call to ModelBuilder, or referenced from a navigation property on a type that is included in the model.

I think this is a limitation of the Entity Framework. You can raise an issue to the EF repo with this question.

My EF Core configuration was:

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 version:

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);
    }
}
Chrissx
  • 357
  • 1
  • 7