我有使用Entity Framework Code First 方法创建的下表。
注意:EntityFramework.dll的运行时版本为 v4.0.30XXX
CODE
public abstract class PaymentComponent
{
public int PaymentComponentID { get; set; }
public int MyValue { get; set; }
public string MyType { get; set; }
public abstract int GetEffectiveValue();
}
public partial class GiftCouponPayment : PaymentComponent
{
public override int GetEffectiveValue()
{
if (MyValue < 2000)
{
return 0;
}
return MyValue;
}
}
public partial class ClubCardPayment : PaymentComponent
{
public override int GetEffectiveValue()
{
return MyValue;
}
}
public partial class Payment
{
public int PaymentID { get; set; }
public List<PaymentComponent> PaymentComponents { get; set; }
public DateTime PayedTime { get; set; }
}
//System.Data.Entity.DbContext is from EntityFramework.dll
public class NerdDinners : System.Data.Entity.DbContext
{
public NerdDinners(string connString): base(connString)
{
}
protected override void OnModelCreating(DbModelBuilder modelbuilder)
{
modelbuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
public DbSet<GiftCouponPayment> GiftCouponPayments { get; set; }
public DbSet<ClubCardPayment> ClubCardPayments { get; set; }
public DbSet<Payment> Payments { get; set; }
}
客户端
static void Main(string[] args)
{
string connectionstring = "Data Source=.;Initial Catalog=NerdDinners;Integrated Security=True;Connect Timeout=30";
using (var db = new NerdDinners(connectionstring))
{
GiftCouponPayment giftCouponPayment = new GiftCouponPayment();
giftCouponPayment.MyValue=250;
giftCouponPayment.MyType = "GiftCouponPayment";
ClubCardPayment clubCardPayment = new ClubCardPayment();
clubCardPayment.MyValue = 5000;
clubCardPayment.MyType = "ClubCardPayment";
List<PaymentComponent> comps = new List<PaymentComponent>();
comps.Add(giftCouponPayment);
comps.Add(clubCardPayment);
var payment = new Payment { PaymentComponents = comps, PayedTime=DateTime.Now };
db.Payments.Add(payment);
int recordsAffected = db.SaveChanges();
}
}
答案 0 :(得分:31)
TPH继承需要特殊列,用于标识实体的类型。默认情况下,此列名为Discriminator
,包含派生实体的名称。您可以使用Fluent-API定义不同的列名称和不同的值。您也可以直接使用MyType列,因为它实际上是一个鉴别器,但在这种情况下,您的实体中不能包含该列(列只能映射一次,如果您将其用作鉴别器,则它已被视为映射)。 p>
可以使用Fluent-API再次控制外键列的名称:
protected override void OnModelCreating(DbModelBuilder modelbuilder)
{
modelbuilder.Conventions.Remove<PluralizingTableNameConvention>();
// Example of controlling TPH iheritance:
modelBuilder.Entity<PaymentComponent>()
.Map<GiftPaymentComponent>(m => m.Requires("MyType").HasValue("G"))
.Map<ClubPaymentComponent>(m => m.Requires("MyType").HasValue("C"));
// Example of controlling Foreign key:
modelBuilder.Entity<Payment>()
.HasMany(p => p.PaymentComponents)
.WithRequired()
.Map(m => m.MapKey("PaymentId"));
}
答案 1 :(得分:8)
如果属性不会映射到列,则添加属性[NotMapped]。
答案 2 :(得分:3)
还可以使用每种类型的表格(TPT)。
每种类型的表(TPT)
每个类型的表是关于将继承关系表示为 关系外键关联。每个类/子类 声明持久属性 - 包括抽象类 - 有自己的属性 表。子类表仅包含每个列 非继承属性(子类本身声明的每个属性) 以及主键,它也是基类的外键 表
在EF Code First中实施TPT
我们可以简单地通过在表上放置Table属性来创建TPT映射 子类指定映射的表名(Table属性是新的 数据注释已添加到 CTP5中的System.ComponentModel.DataAnnotations命名空间。
如果您更喜欢流畅的API,那么您可以使用创建TPT映射 ToTable()方法:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BankAccount>().ToTable("BankAccounts");
modelBuilder.Entity<CreditCard>().ToTable("CreditCards");
}
答案 3 :(得分:1)
当您使用子类时,需要使用Discriminator列来区分每种类型的子类。
答案 4 :(得分:0)
由于“GiftCouponPayment”和“ClubCardPayment”都来自“PaymentComponent”,因此EF不会使用单独的表,而是需要该列。如果你想要一个不同的行为,你必须覆盖默认的表访问并将字段映射到你的类(我认为你不想这样做)不确定是否有一个简单的方法来实现。从实体开始,我知道有一种方法可以通过模板创建表格。
外键列名称也是如此。 EF使用这种方式为key / foreignkey名称创建名称。如果你想根据自己的喜好对表进行格式化,你必须自己完成这一切,这就产生了为什么要使用EF的问题。
除了化妆品之外,你有什么理由想要这样做吗?
答案 5 :(得分:0)
示例代码,用于删除Discriminator列并将名为PaymentId的列作为鉴别符,从而解决您的问题。基于Microsofts Fluent Api原始文档。
https://msdn.microsoft.com/en-us/library/jj591617%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396
public enum MyEnum
{
Value1, Value2
}
public class MyBaseClass
{
[NotMapped]
public MyEnum PaymentId { get; protected set; }
}
public class DerivedOne: MyBaseClass
{
public DerivedOne()
{
PaymentId = MyEnum.Value1;
}
}
public class DerivedTwo: MyBaseClass
{
public DerivedTwo()
{
PaymentId = MyEnum.Value2;
}
}
public class MyDbContext : DbContext
{
DbSet<MyBaseClass> MyBaseClass { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyBaseClass>()
.Map<DerivedOne>(x => x.Requires("PaymentId").HasValue((int)PaymentId.Value1))
.Map<DerivedTwo>(x => x.Requires("PaymentId").HasValue((int)PaymentId.Value2));
}
}
答案 6 :(得分:0)
为了避免表中的Discriminator列,您只需要在派生类上添加注释[NotMapped]。