我已经搜索了几个小时,我似乎无法找到问题。
我正在构建一个实体框架Fluent Api Code First TPH应用程序。当我添加 - 迁移EF添加我的“类型”列时,它还添加了一个冗余的Discriminator列(它应该被“Type”覆盖)。我使用Map来指定Type列名和可能的值,这种方法似乎适用于大多数域模型,但是这个方法获得了冗余的第二个鉴别器列,我似乎无法找到原因。 Bond继承自域模型中的Asset。
继承我的代码:
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));
}
}
域名模型:
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();
}
}
答案 0 :(得分:3)
使用任何EF6继承时必须非常小心。 EF使用反射来发现同一程序集中的所有类,这些类直接或间接地继承了作为EF继承一部分的某些实体,并将它们视为实体层次结构的一部分,即使它们未被使用/引用/配置在任何地方。 EF模型。
所以只需添加另一个类(在您的实际情况下称为Equity
)
public Asset2 : Asset { }
足以引入标准Discriminator
列,因为它未配置为使用Bond
类的鉴别器列设置。
此行为是您的意外错误的来源,并且在EF Core中已更改,其中仅考虑显式配置的派生类。
在EF6中,使用NotMapped
属性标记此类,使用Ignore
流畅的API或将其正确映射为实体。
答案 1 :(得分:1)
这是一个完整的非复制品。确保您的EntityTypeConfiguration在OnModelCreating中连线,并且在初始化模型时实际运行。也不要为带有“tbl_”前缀的表命名。
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])
)