实体框架:如何从表中避免Discriminator列?

时间:2012-07-24 12:06:23

标签: c# .net entity-framework ef-code-first

我有使用Entity Framework Code First 方法创建的下表。

  1. 如何修改C#代码,以便不在数据库中创建不需要的Discriminator列?是否有任何属性可以实现?
  2. 如何将外键列名称设为“PaymentID”而不是“Payment_ PaymentID”?是否有任何属性可以实现?
  3. 注意:EntityFramework.dll的运行时版本为 v4.0.30XXX

    enter image description here

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

7 个答案:

答案 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)。

http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-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]。