2012-07-24 48 views
23

我用下面的表格創建了使用實體框架Code First的方法。實體框架:如何避免表中的Discriminator列?

  1. 如何修改C#代碼以便在數據庫中不創建不想要的Discriminator列?有沒有什麼屬性可以實現這一點?
  2. 如何使外鍵列名稱爲「PaymentID」而不是「Payment_ PaymentID」?有沒有什麼屬性可以實現這一點?

注: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; } 

} 

CLIENT

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


     } 

    } 
+2

如果您重寫約定,其他開發人員將難以理解您的模式。學習和使用約定會更有益,例如,在閱讀其他開發人員的代碼或默認生成的代碼時,您不必提問,也無需編寫其他代碼。 – user3285954 2014-12-29 11:21:00

回答

29

TPH繼承需要特殊的列來識別實體的類型。默認情況下,該列被稱爲Discriminator幷包含派生實體的名稱。您可以使用Fluent-API來定義不同的列名稱和不同的值。你也可以直接使用你的MyType列,因爲它實際上是一個鑑別器,但在這種情況下,你的實體中不能有該列(列只能映射一次,如果你使用它作爲鑑別器,它已經被認爲是映射)。

外鍵列的名稱可以再次控制用流利的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

正如您使用的是子類,Discriminator列需要區分每種類型的子類。

0

由於「GiftCouponPayment」和「ClubCardPayment」都來自「PaymentComponent」,因此EF不會使用單獨的表並且需要該列。如果你想要一個不同的行爲,你將不得不重寫默認的表訪問並將這些字段映射到你的類(我認爲你不想這樣做)不確定是否有一個簡單的方法來實現。從實體首先,我知道有一種方法可以創建表格。
對於外鍵列名稱也是如此。 EF使用這種方式爲鍵/外鍵名稱創建名稱。如果你想按照自己的喜好來設置表格的格式,那麼你必須自己做所有的事情,這就導致了爲什麼要使用EF的問題。
除了化妝品之外,您還有什麼特別的理由要這樣做?

4

也可以使用每個類型(TPT)表。

http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-2-table-per-type-tpt

每個表類型(TPT)

每表型是關於代表繼承關係作爲 關係外鍵關聯。 聲明持久屬性的每個類/子類(包括抽象類)都有其自己的 表。子類的表包含僅針對每個 非後繼屬性(由子類本身聲明的每個屬性) 的列以及主鍵,該主鍵也是基類 表的外鍵。

在EF代碼首先實現TPT

我們可以簡單地通過將表屬性上 子類來指定映射表名(表屬性是一個新的 數據標註,並已加入到 創建TPT映射。

:System.ComponentModel.DataAnnotations命名空間中CTP5

如果你喜歡流暢的API,那麼你可以通過使用 ToTable()方法創建一個映射TPT 0

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<BankAccount>().ToTable("BankAccounts"); 
    modelBuilder.Entity<CreditCard>().ToTable("CreditCards"); 
} 
+0

請注意,性能問題時,不推薦TP用於EF。請參閱:https://msdn.microsoft.com/en-US/data/hh949853下7.1.1 – 2015-06-12 12:26:10

7

如果屬性不會映射到列,則添加屬性[NotMapped]。

+2

此外,添加[NotMapped]作爲類屬性有助於當您不希望EF將您的子類映射到數據庫表 – kape123 2016-04-03 07:46:26

+0

感謝 - 你正是我要找的答案! – Jocie 2016-04-07 09:28:10

+0

如果你喜歡使用Fluent API而不是屬性/註釋,你可以編輯你的_DbContext_並在_OnModelCreating_方法中添加:** modelBuilder.Ignore (); ** – Rostov 2016-10-27 14:32:44

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

爲了避免從表鑑別列,你只需要添加註釋[NotMapped]在你的派生類。

相關問題