26

私は Entity Framework 4 CTP5 コードの最初のアプローチを使用しており、階層ごとのテーブル (TPH) マッピングを使用しています。階層内のいくつかのクラスには、共通のプロパティがあります。

public class BaseType
{
    public int Id { get; set; }
}

public class A : BaseType
{
    public string Customer { get; set; }
    public string Order { get; set; }
}

public class B : BaseType
{
    public string Customer { get; set; }
    public string Article { get; set; }
}

public class C : BaseType
{
    public string Article { get; set; }
    public string Manufacturer { get; set; }
}

デフォルトの規則では、これを次の列にマップします。

  • ID
  • 第1条
  • 第2条
  • 顧客1
  • 顧客2
  • メーカー
  • 注文
  • タイプ

EF4 で共通のプロパティを共有して、最終的に次のようにしたいと考えています。

  • ID
  • 論文
  • お客様
  • メーカー
  • 注文
  • タイプ

列数の削減とは別に、これには、たとえば Article に基づいてレコードを検索できるという利点があります。どのタイプが Article プロパティを正確に持っているかを知る必要はありません。

各共通プロパティを同じ列にマッピングしてみました:

modelBuilder.Entity<B>().Property(n => n.Article).HasColumnName("Article");
modelBuilder.Entity<C>().Property(n => n.Article).HasColumnName("Article");

しかし、これは次の例外をスローしました:

指定されたスキーマは無効です。エラー: (36,6): エラー 0019: 型の各プロパティ名は一意である必要があります。プロパティ名 'Article' は既に定義されています。

この検証ルールを回避する方法を知っている人はいますか?

4

2 に答える 2

20

この検証をバイパスする回避策はありません。TPH では、列は、すべての子によって継承される基本クラスに属するか、子クラスに特化されます。EF にそれを 2 つの子にマップするように指示することはできませんが、もう一方にはマップすることはできません。そうしようとすると (たとえば、[Column(Name = "Customer")]A.Customer と B.Customer の両方を配置することによって)、次のメッセージでMetadataExceptionが発生します。

指定されたスキーマは無効です。エラー: (10,6): エラー 0019: 型の各プロパティ名は一意である必要があります。プロパティ名 'Customer' は既に定義されています。


TPH ソリューション:

Customerこれに対する 1 つの解決策は、Articleプロパティを基本クラスに昇格させることです。

public class BaseType {
    public int Id { get; set; }
    public string Customer { get; set; }
    public string Article { get; set; }
}

public class A : BaseType {
    public string Order { get; set; }
}

public class B : BaseType { }

public class C : BaseType {
    public string Manufacturer { get; set; }
}

目的のスキーマの結果:

代替テキスト


TPT ソリューション (推奨):

とはいえ、シナリオにより適しているため、Type per Type (TPT) の使用を検討することをお勧めします。

public class BaseType
{
    public int Id { get; set; }
}

public class A : BaseType
{
    [Column(Name = "Customer")]
    public string Customer { get; set; }
    public string Order { get; set; }
}

public class B : BaseType
{
    [Column(Name = "Customer")]
    public string Customer { get; set; }

    [Column(Name = "Article")]
    public string Article { get; set; }
}

public class C : BaseType
{
    [Column(Name="Article")]
    public string Article { get; set; }
    public string Manufacturer { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<BaseType> BaseTypes { get; set; }        

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<BaseType>().ToTable("BaseType");
        modelBuilder.Entity<A>().ToTable("A");
        modelBuilder.Entity<C>().ToTable("C");
        modelBuilder.Entity<B>().ToTable("B");          
    }
}

代替テキスト

于 2010-12-08T16:51:33.293 に答える
8

この問題で問題を抱えていた人のために、EF6: エンティティ フレームワーク - Codeplexで修正されました。

于 2013-04-02T04:02:28.450 に答える