C# 实体框架将冗余的重复鉴别器列添加到表中

C# 实体框架将冗余的重复鉴别器列添加到表中,c#,entity-framework,entity-framework-6,ef-fluent-api,table-per-hierarchy,C#,Entity Framework,Entity Framework 6,Ef Fluent Api,Table Per Hierarchy,我已经搜索了好几个小时,但似乎找不到问题所在 我正在构建实体框架Fluent Api代码第一个TPH应用程序。当我添加Migration EF Add时,我的“Type”列很好,但它也添加了一个冗余的鉴别器列(它应该被“Type”覆盖)。我使用Map来指定类型列名和可能的值,这种方法似乎对大多数域模型都很有效,但这一个得到了冗余的第二个鉴别器列,我似乎找不到原因。债券继承自域模型中的资产 这是我的密码: public class BondConfiguration : EntityTypeCon

我已经搜索了好几个小时,但似乎找不到问题所在

我正在构建实体框架Fluent Api代码第一个TPH应用程序。当我添加Migration EF Add时,我的“Type”列很好,但它也添加了一个冗余的鉴别器列(它应该被“Type”覆盖)。我使用Map来指定类型列名和可能的值,这种方法似乎对大多数域模型都很有效,但这一个得到了冗余的第二个鉴别器列,我似乎找不到原因。债券继承自域模型中的资产

这是我的密码:

public class BondConfiguration : EntityTypeConfiguration<Bond>
{
    public BondConfiguration()
    {
        Property(b => b.IssueDate)
            .HasColumnName("BondIssueDate")
            .HasColumnType(DatabaseVendorTypes.TimestampField)
            .IsRequired();

        Property(b => b.MaturityDate)
            .HasColumnName("BondMaturityDate")
            .HasColumnType(DatabaseVendorTypes.TimestampField)
            .IsRequired();

        HasRequired(b => b.Currency).WithRequiredDependent();

        Property(b => b.Coupon.Rate);

        Property(b => b.Coupon.Amount);

        Property(b => b.FaceValue)
            .HasColumnName("BondFaceValue")
            .IsRequired();
    }
}

public class AssetConfiguration : EntityTypeConfiguration<Asset>
{
    public AssetConfiguration()
    {
        Property(a => a.IsDeleted).HasColumnName("IsDeleted");

        HasKey(a => a.Id);

        ToTable("tbl_Asset");

        Property(a => a.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
            .HasColumnName("AssetId");

        Property(a => a.Name)
            .HasColumnName("AssetName")
            .IsRequired();

        Property(a => a.Isin)
            .HasColumnName("AssetISIN");

        Map<Bond>(p => p.Requires("AssetClass").HasValue((int)AssetClass.Bond));
    }
}
公共类绑定配置:EntityTypeConfiguration
{
公共配置()
{
属性(b=>b.IssueDate)
.HasColumnName(“债券发行人”)
.HasColumnType(DatabaseVendorTypes.TimestampField)
.IsRequired();
财产(b=>b.到期日)
.HasColumnName(“债券到期日”)
.HasColumnType(DatabaseVendorTypes.TimestampField)
.IsRequired();
HasRequired(b=>b.Currency)。WithRequiredDependent();
房地产(b=>b.息票率);
财产(b=>b.息票金额);
属性(b=>b.FaceValue)
.HasColumnName(“BondFaceValue”)
.IsRequired();
}
}
公共类资产配置:EntityTypeConfiguration
{
公共资产配置()
{
属性(a=>a.IsDeleted).HasColumnName(“IsDeleted”);
HasKey(a=>a.Id);
可转让资产(“待转让资产”);
属性(a=>a.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.HasColumnName(“AssetId”);
属性(a=>a.Name)
.HasColumnName(“资产名称”)
.IsRequired();
属性(a=>a.Isin)
.HasColumnName(“资产”);
Map(p=>p.Requires(“AssetClass”).HasValue((int)AssetClass.Bond));
}
}
域模型:

public class Bond : Asset
{
    public DateTime IssueDate { get; set; }

    public DateTime MaturityDate { get; set; }

    public BondCoupon Coupon { get; set; }

    public Currency Currency { get; set; }

    public decimal FaceValue { get; set; }

    public IEnumerable<ValidationRule> SetCoupon(decimal amount, decimal rate)
    {
        var newCoupon = new BondCoupon
        {
            Rate = rate,
            Amount = amount
        };

        if (Validate(new SetBondCouponValidator(newCoupon),out IEnumerable<ValidationRule> brokenRules))
        {
            Coupon = new BondCoupon
            {
                Rate = rate,
                Amount = amount
            };
        }
        return brokenRules;
    }
}

public abstract class BaseAsset<T> : BaseEntity<T> where T : BaseEntity<T>, new()
{
    public string Name { get; set; }

    public string Isin { get; set; }
}

public class Asset : BaseAsset<Asset>, IEntityRoot
{
}

public class BaseEntity<T> where T : BaseEntity<T>, new()
{
    public int Id { get; set; }

    public bool IsDeleted { get; set; }

    public bool Validate(IValidator validator, out IEnumerable<ValidationRule> brokenRules)
    {
        brokenRules = validator.GetBrokenRules();
        return validator.IsValid();
    }
}
公共类债券:资产
{
公共日期时间发布日期{get;set;}
公共日期时间到期日期{get;set;}
公共债券息票{get;set;}
公共货币{get;set;}
公共十进制面值{get;set;}
公共IEnumerable Set息票(十进制金额、十进制利率)
{
var new息票=新债券息票
{
比率=比率,
金额=金额
};
if(验证(新SetBondCouponValidator(新优惠券),输出IEnumerable BrokerRules))
{
息票=新债券息票
{
比率=比率,
金额=金额
};
}
返回中断规则;
}
}
公共抽象类BaseAsset:BaseEntity,其中T:BaseEntity,new()
{
公共字符串名称{get;set;}
公共字符串为{get;set;}
}
公共类资产:BaseAsset、IEntityRoot
{
}
公共类BaseEntity,其中T:BaseEntity,new()
{
公共int Id{get;set;}
公共布尔被删除{get;set;}
公共bool验证(IValidator验证程序,out IEnumerable BrokerRules)
{
brokenRules=validator.GetBrokenRules();
返回validator.IsValid();
}
}

这是一个完全不可复制的程序。确保EntityTypeConfiguration在OnModelCreating中连接,并在初始化模型时实际运行。也不要用“tbl_u2;”前缀命名表


这是一个完全不可重复的例子。确保EntityTypeConfiguration在OnModelCreating中连接,并在初始化模型时实际运行。也不要用“tbl_u2;”前缀命名表


使用任何EF6继承时都必须非常小心。EF使用反射发现同一程序集中的所有类,这些类直接或间接继承属于EF继承的某些实体,并将它们视为实体层次结构的一部分,即使它们未在EF模型的任何位置使用/引用/配置

因此,只需添加另一个类(在您的实际案例中,它被称为
Equity

足够引入标准的
鉴别器
列,因为它没有配置为使用
绑定
类的鉴别器列设置

这种行为是像您这样的意外错误的来源,并且在EF Core中已被更改,其中只考虑显式配置的派生类


在EF6中,要么用
NotMapped
属性标记此类类,要么使用
Ignore
fluent API,要么将它们正确地映射为实体。

使用任何EF6继承时都必须非常小心。EF使用反射发现同一程序集中的所有类,这些类直接或间接继承属于EF继承的某些实体,并将它们视为实体层次结构的一部分,即使它们未在EF模型的任何位置使用/引用/配置

因此,只需添加另一个类(在您的实际案例中,它被称为
Equity

足够引入标准的
discribator
列,因为它未配置为使用
Bond
类的鉴别器列设置

这种行为是像您这样的意外错误的来源,并且在EF Core中已被更改,其中只考虑显式配置的派生类


在EF6中,可以使用
NotMapped
属性标记这些类,使用
Ignore
fluent API,或者将它们正确地映射为实体。

您是否可以添加
资产
Bond
类,以便我们可以重现问题?我刚刚添加了域模型。谢谢你看这个。不能用提供的模型复制。同一项目(程序集)中是否有继承
资产
债券
的其他类?整个代码库托管在Github上:我看到
股权
类继承
资产
。您可能认为它不可发现(因为没有明确的引用)
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.Data.SqlClient;
using System.Linq;

namespace ConsoleApp8
{

    public class Bond : Asset
    {
        public DateTime IssueDate { get; set; }

        public DateTime MaturityDate { get; set; }

        //public BondCoupon Coupon { get; set; }

        //public Currency Currency { get; set; }

        public decimal FaceValue { get; set; }


    }

    public abstract class BaseAsset<T> : BaseEntity<T> where T :  new()
    {
        public string Name { get; set; }

        public string Isin { get; set; }
    }

    public class Asset : BaseAsset<Asset>
    {
    }

    public class BaseEntity<T> where T :  new()
    {
        public int Id { get; set; }

        public bool IsDeleted { get; set; }


    }
    public class BondConfiguration : EntityTypeConfiguration<Bond>
    {
        public BondConfiguration()
        {

            Property(b => b.FaceValue)
                .HasColumnName("BondFaceValue")
                .IsRequired();
        }
    }
    public  enum  AssetClass
    {
        Bond = 1
    }
    public class AssetConfiguration : EntityTypeConfiguration<Asset>
    {
        public AssetConfiguration()
        {
            Property(a => a.IsDeleted).HasColumnName("IsDeleted");

            HasKey(a => a.Id);

            ToTable("Asset");

            Property(a => a.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
                .HasColumnName("AssetId");

            Property(a => a.Name)
                .HasColumnName("AssetName")
                .IsRequired();

            Property(a => a.Isin)
                .HasColumnName("AssetISIN");

            Map<Bond>(p => p.Requires("AssetClass").HasValue((int)AssetClass.Bond));
        }
    }

    class Db : DbContext
    {
        public DbSet<Bond> Bonds { get; set; }
        public DbSet<Asset> Assets { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new AssetConfiguration());
            modelBuilder.Configurations.Add(new BondConfiguration());
        }
    }



    class Program
    {      

        static void Main(string[] args)
        {

            Database.SetInitializer(new DropCreateDatabaseAlways<Db>());

            using (var db = new Db())
            {
                db.Database.Log = m => Console.WriteLine(m);

                db.Database.Initialize(true);






            }


            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();


        }
    }
}
CREATE TABLE [dbo].[Asset] (
    [AssetId] [int] NOT NULL IDENTITY,
    [AssetName] [nvarchar](max) NOT NULL,
    [AssetISIN] [nvarchar](max),
    [IsDeleted] [bit] NOT NULL,
    [IssueDate] [datetime],
    [MaturityDate] [datetime],
    [BondFaceValue] [decimal](18, 2),
    [AssetClass] [int],
    CONSTRAINT [PK_dbo.Asset] PRIMARY KEY ([AssetId])
)
public Asset2 : Asset { }