2012-04-07 7 views
1

私は最初にコードでEFを少し試しています。私はどこに間違っているのか分かりません。私はちょうどアイデアがなくなり、私が間違っている場所を釘付けにしたいと思っています...TPHシンプルな設定/ディスクリミネータの問題

最初に場所を表すPOCOクラス - 場所は、RadioStation、またはMerchantです。私は追加のフィールドを追加していません(これは後で来ます)。今は単純な設定でTPHを作っています。

namespace EFDataClasses.Entities 
{ 

    public class RadioStation : Location 
    { 
    public RadioStation() 
    { 
    } 

    } 

    public class Merchant : Location 
    { 
    public Merchant() 
    { 
    } 
    } 


    public class Location 
    { 
    public Location() 
    { 

    } 

public int Loc_ID { get; set; } 
public string Loc_Code { get; set; } 
public string Loc_Name { get; set; } 
public string Loc_Type {get;set;} 

} 
} 

その後、Configクラス:ここ

namespace EFDataClasses.Mapping 
{ 


    public class LocationMap : EntityTypeConfiguration<Location> 
    { 
    public LocationMap() 
    { 
     // Primary Key 
     this.HasKey(t => t.Loc_ID); 

     // Properties 
     this.Property(t => t.Loc_ID) 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

     // Properties 
     this.Property(t => t.Loc_Code) 
      .IsRequired() 
      .HasMaxLength(50); 

     this.Property(t => t.Loc_Name) 
      .IsRequired() 
      .HasMaxLength(50); 


     this.Property(t => t.Loc_ID).HasColumnName("Loc_ID"); 
     this.Property(t => t.Loc_Code).HasColumnName("Loc_Code"); 
     this.Property(t => t.Loc_Name).HasColumnName("Loc_Name"); 

     //my discriminator property 
     this.Property(t => t.Loc_Type).HasColumnName("Loc_Type").HasColumnType("varchar").HasMaxLength(50).IsRequired(); 

     // Table & Column Mappings 
     this.Map(m => 
     { 
     m.ToTable("Location"); 
     m.Requires("Loc_Type").HasValue("Location"); 
     } 
     ) 
     .Map<RadioStation>(m => 
     { 
      m.ToTable("Location"); 
      m.Requires("Loc_Type").HasValue("RadioStation"); 
     } 
     ) 
     .Map<Merchant>(m => 
     { 
      m.ToTable("Location"); 
      m.Requires("Loc_Type").HasValue("Merchant"); 
     } 
     ) 
     ; 



    } 
    } 
} 

はコンテキストです..ラジオ局を追加しようと

namespace EFDataClasses 
{ 
    public class MyContext : DbContext 
    { 
    static MyContext() 
    { 
     Database.SetInitializer<MyContext>(new DropCreateDatabaseAlways<MyContext>()); 
    } 

    public DbSet<EFDataClasses.Entities.Location> Locations {get; set;} 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Configurations.Add(new LocationMap()); 
    } 
    } 
} 

、最終的にはプログラムのクラス

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace EFConsole 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 

     var db = new EFDataClasses.MyContext(); 
     db.Locations.Add(new EFDataClasses.Entities.RadioStation() { Loc_Name = "Radio Station Name 1", Loc_Code = "RD1" }); 
     int chngs = db.SaveChanges(); 
     System.Diagnostics.Debugger.Break(); 

    } 
    } 
} 

私はエラーですLoc_Typeの検証エラーです。必須フィールドです。私の印象は、適切なタイプを選択したときにEFがそれを記入することです。

私は、適切な場所の種類を追加した場合は - EFは私に別のエラーを与える....

arggghhhを!

最終的に私はLocation Abstractを作成したいと思いますが、それは私がhasvalue( "Location")を削除できるということですか?

私はここに進んでいきたいと思いますが、私が間違っていた場所は不思議です。ありがとう!

答えて

0

問題は、TPHマッピングのディスクリミネータとして列を使用する場合、その列をクラス内のプロパティにマップできないということです。これは、現在、EFが.NETクラスのタイプに基づいてその列の値を制御しているためです。あなたが必要とする(またはしたい)場合は、識別子列のためなど、サイズを明示的に列の型を指定する

// Remove this line: 
this.Property(t => t.Loc_Type).HasColumnName("Loc_Type").HasColumnType("varchar").HasMaxLength(50).IsRequired(); 

ことができます。だから、場所列にLoc_Typeプロパティのマッピングを行い、この行を削除する必要がありますマップ呼び出しでそれを行います。例:

Map(m => 
{ 
    m.ToTable("Location"); 
    m.Requires("Loc_Type") 
     .HasValue("Location") 
     .HasColumnType("varchar") 
     .HasMaxLength(50) 
     .IsRequired(); 
} 

ロケーションタイプを表すクラスにプロパティを持つ必要はありません。あなたがLoc_Typeの文字列値相当を取得したいならば、あなたは場所でこのようなものを使用することができます。

public virtual string Loc_Type 
{ 
    get { return "Location"; } 
} 

その後、他のクラスでそれを上書きします。例:

public override string Loc_Type 
{ 
    get { return "RadioStation"; } 
} 

残りのコードは正常です。

+0

私はあなたが正しいところにいると思いますが、どうしてEFにマッピングファイルに各サブクラスの値を伝えてから、Loc_Typeのプロパティをオーバーライドする必要があるのか​​混乱していますか?私は、弁別子フィールドの名前とサイズを制御したいと思っています。 – codeputer

+0

Loc_Typeプロパティをオーバーライドする必要はありません。私はあなたがその財産の価値を望むならば、それを示していただけです。 discriminatorフィールドのサイズを設定する場合は、マップ呼び出しでそれを行います。私はこれを表示するために私の答えを更新します。 –

+0

ここでの私の大きな混乱は、FKの分野に貢献し、リレーションシップに流暢なAPIを使用していることを実感しました。この場合、クラスのFKフィールドをマッピングしますが、識別器の場合はFKフィールドをマッピングしません。私はこのような理由から弁別者をクラスから削除することは考えていませんでした。これはAPI設計の不一致であると私には思われます。どう思いますか? – codeputer

1

私はあなたが少し複雑すぎると思います。それはCFの周りで危険です。
コードファーストでは、「試してテストした」パターンに固執する必要があります。そうでなければ、物と構造を混ぜるとすぐに問題が発生します。

まず、なぜLoc_Typeをマップして取得する必要があるのですか。私はクラスモデルを意味しますか?それは余分です、あなたはあなたの 'クラス'タイプで実際にそれを得るでしょう、あなたのクラスタイプは弁別者であり、その逆もあります。

これは、私が思うに、「マッピングから列を削除する」か、何かを供給していると思われるエラーです。

ちょうどそれを'Location'から削除しても問題ありません。また、あなたはあなたのDbを理にかなって他の側などで使用したい場合を除いて、ほとんどの場合弁別子を指定する必要はありません。

あなたが抽象的にすることができれば、場所 - それは普通に行われ、マッピングからそれを削除することができると思います。

そして最後に、TPHはいろいろな理由から、最も幸運な解決策ではなく、私が思うところで最も誤りの多いTPT、TPCはもっと "流動的"に機能します。あなたは '子クラス'のプロパティをnull以外にすることはできません。

これが役に立ちます。

EDIT:あなたは「隠れた」弁別を制御したい場合I thinkあなたが試みることができるし、手動でそれが重要な場合、それはサイズなどだ設定するには、特にその列のmigration fileを調整(コードでは、まず右の値を選ぶ必要がありますそこに私は推測する)。どのようなものがうまくいかなければならないという意味で重要なものを変更しなければならない。

+0

NSGaga - 私はあなたがクラス側から何を言っているかを聞いていますが、規約と必要性に関係なく、まずDiscriminatorという列を追加します。フィールドのマッピングでDiscriminatorフィールドの名前とサイズを制御したいだけです。このフィールドをプライベートにすることができれば(それはできますか?)、それはさらに優れています。私はこの技術を採用したいと思っていますが、今は私のDB設計を好んで、主にTable-per-Typeに固執しています! – codeputer

+0

あなたは手動でマイグレーションファイルを調整することで詳細を制御することができますが、それはそのトリックを行います。 'プライベート'、それは動作するかどうか、あなたがマッピングしている場合は、それをマッピングしている、私はあなたがそれを離れる必要があると思います。そして、@Arthurはこれと同じことを言って、彼はMSからこのようなことに取り組んでいる人だから、私が推測していることを知っておくべきです。 – NSGaga

+0

table-per-typeについて言及することに注意してください。 EF Code Firstでこれを行うこともできます。 TPH、TPT、TPC(コンクリートクラスごとのテーブル)を行うことができます。これは、オプションとそれを行う方法を説明する素晴らしい一連の投稿です:http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code- first-ctp5-part-1-table-per-hierarchy-tph.aspx –