EF Core 6 is generating duplicate foreign keys on base type and inherited types when scripting the dbcontext

218 Views Asked by At

I have an existing database using table per type inheritance. The BaseTypes table has a primary key with two columns (Id and ShopCode) and a named foreign key (FK_BaseType_Shops) to another table (Shops) using the ShopCode column.

There are two inherited tables ATypes and BTypes that also have primary keys of Id and ShopCode, but they do not have foreign keys to the Shops table (because that should be inherited).

When I try to generate a SQL script from the DbContext, the BaseTypes table and the inherited ATypes and BTypes tables are all getting the foreign key assigned with the same name.

I'm pretty new to EF core/model first. Can anyone tell me if I am just missing something, or if this is a bug in EF Core?

Here are the models:

public abstract class BaseType
{
    public string Id { get; set; }
    public string ShopCode { get; set; } = null!;
    public string Name { get; set; } = null!;

    public virtual Shop Shop { get; set; } = null!;
}
public partial class AType : BaseType
{
    public string? Property1 { get; set; }
}
public partial class BType : BaseType
{
    public string? Property2 { get; set; }
}
public partial class Shop
{
    public string ShopCode { get; set; } = null!;
    public string ShopName { get; set; } = null!;
}

Here is the DbContext:

public partial class myContext : DbContext
{
    private string _connectionString =
        "Server=(localdb)\\mssqllocaldb;Database=TestDB;Trusted_Connection=True";
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer(_connectionString);
        }
    }

    public virtual DbSet<BaseType> BaseTypes { get; set; } = null!;
    public virtual DbSet<AType> ATypes { get; set; } = null!;
    public virtual DbSet<BType> BTypes { get; set; } = null!;
    public virtual DbSet<Shop> Shops { get; set; } = null!;
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        try
        {
            modelBuilder.Entity<AType>(entity =>
            {
                entity.ToTable("ATypes").HasBaseType<BaseType>();
            });

            modelBuilder.Entity<BaseType>(entity =>
            {
                entity.ToTable("BaseTypes").HasKey(e => new{e.Id, e.ShopCode});

                entity.HasOne(e => e.Shop)
                    .WithMany()
                    .HasConstraintName("FK_BaseType_Shops")
                    .OnDelete(DeleteBehavior.NoAction);

            });

            modelBuilder.Entity<BType>(entity =>
            {
                entity.ToTable("BTypes").HasBaseType<BaseType>();
            });

            modelBuilder.Entity<Shop>(entity =>
            {
                entity.HasKey(e => e.ShopCode);
            });

            
        }
        catch
        {
            throw;
        }
        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

Here is the SQL that gets generated when I run Script-DbContext -Context myContext -Output "create database.sql" from the package manager console:

CREATE TABLE [Shops] (
    [ShopCode] nvarchar(450) NOT NULL,
    [ShopName] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_Shops] PRIMARY KEY ([ShopCode])
);
GO


CREATE TABLE [BaseTypes] (
    [Id] nvarchar(450) NOT NULL,
    [ShopCode] nvarchar(450) NOT NULL,
    [Name] nvarchar(max) NOT NULL,
    CONSTRAINT [PK_BaseTypes] PRIMARY KEY ([Id], [ShopCode]),
    CONSTRAINT [FK_BaseType_Shops] FOREIGN KEY ([ShopCode]) REFERENCES [Shops] ([ShopCode])
);
GO


CREATE TABLE [ATypes] (
    [Id] nvarchar(450) NOT NULL,
    [ShopCode] nvarchar(450) NOT NULL,
    [Property1] nvarchar(max) NULL,
    CONSTRAINT [PK_ATypes] PRIMARY KEY ([Id], [ShopCode]),
    CONSTRAINT [FK_ATypes_BaseTypes_Id_ShopCode] FOREIGN KEY ([Id], [ShopCode]) REFERENCES [BaseTypes] ([Id], [ShopCode]),
    CONSTRAINT [FK_BaseType_Shops] FOREIGN KEY ([ShopCode]) REFERENCES [Shops] ([ShopCode])
);
GO


CREATE TABLE [BTypes] (
    [Id] nvarchar(450) NOT NULL,
    [ShopCode] nvarchar(450) NOT NULL,
    [Property2] nvarchar(max) NULL,
    CONSTRAINT [PK_BTypes] PRIMARY KEY ([Id], [ShopCode]),
    CONSTRAINT [FK_BaseType_Shops] FOREIGN KEY ([ShopCode]) REFERENCES [Shops] ([ShopCode]),
    CONSTRAINT [FK_BTypes_BaseTypes_Id_ShopCode] FOREIGN KEY ([Id], [ShopCode]) REFERENCES [BaseTypes] ([Id], [ShopCode])
);
GO


CREATE INDEX [IX_ATypes_ShopCode] ON [ATypes] ([ShopCode]);
GO


CREATE INDEX [IX_BaseTypes_ShopCode] ON [BaseTypes] ([ShopCode]);
GO


CREATE INDEX [IX_BTypes_ShopCode] ON [BTypes] ([ShopCode]);
GO
0

There are 0 best solutions below