2012-07-24 12 views
23

エンティティフレームワークコードを使用して次の表を作成しました。アプローチ。Entity Framework:Discriminatorカラムをテーブルから避けるには?

  1. 不要なDiscriminator列がデータベースに作成されないようにC#コードを変更するにはどうすればよいですか?それを達成するための属性はありますか?
  2. 「Payment_ PaymentID」ではなく「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

答えて

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

サブクラスを使用している場合は、サブクラスの各タイプを区別するために「ディスクリミネータ」列が必要です。

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)当たり表当たりの種類 リレーショナル外部キーの関連付けとして継承関係を示す程度です。 が抽象クラスを含む永続プロパティを宣言するすべてのクラス/サブクラスには、独自の テーブルがあります。サブクラスのテーブルには、それぞれ 非継承プロパティ(サブクラス自体で宣言された各プロパティ)の列のみが含まれます。 プライマリキーは、基本クラス テーブルの外部キーです。

(表属性が新しい データ注釈であると に追加されました私たちは、マッピングされたテーブル名を指定するだけで サブクラスの表属性を配置することによって、TPTのマッピングを作成することができますEFコードファースト

にTPTを実装。

:あなたは流暢なAPIを好む場合CTP5でSystem.ComponentModel.DataAnnotations名前空間

、あなたは ToTable()メソッドを使用して、TPTのマッピングを作成することができます0

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

パフォーマンスが問題になる場合、TPTはEFには推奨されません。参照:https://msdn.microsoft.com/en-US/data/hh949853 7.1.1 –

7

プロパティを[NotMapped]に設定すると、プロパティが列にマップされません。

+2

また、クラス属性として[NotMapped]を追加すると、EFがサブクラスをデータベーステーブルにマップしたくない場合に役立ちます – kape123

+0

ありがとう - あなた、私が探していた答えがまさに! – Jocie

+0

属性/注釈の代わりにFluent APIを使用する場合は、_DbContext_を編集し、_OnModelCreating_メソッドで次を追加することができます。** modelBuilder.Ignore (); ** – Rostov

0

Discriminator列を削除し、代わりにDiscreteizerとしてPaymentIdという名前の列を取得するサンプルコードです。したがって、両方の質問を解決します。 Microsoftの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]注釈を追加する必要がテーブルから識別子列を避けるために。

関連する問題