2016-11-14 10 views
0

EF6を使用してCodeFirstアプローチで新しいアプリケーションで既存のDBを変換する必要があります。私は継承のマッピング規則を使って戦っています。エンティティフレームワーク6タイプごとのテーブル継承のカスタムキー

親と子の2つのテーブルがあるとします。

CREATE TABLE A_PARENT (
    A_PAR_ParentId UNIQUEIDENTIFIER PRIMARY KEY, 
    A_PAR_data VARCHAR(255) 
) 

CREATE TABLE B_CHILD (
    B_CHL_ChildId UNIQUEIDENTIFIER PRIMARY KEY FOREIGN KEY REFERENCES A_PARENT(A_PAR_ParentId), 
    B_CHL_childData VARCHAR(255) 
) 

私はあなたが見ることができるテーブルのプリフィックスを成功裏に解決しました。このようなカスタム属性を使用する「A_PAR」。私は、EFがどんなプロパティがどの列に属し、どの列が主キーであるかを正確に知っていると信じています。継承を除いてすべてうまく動作します。

SELECT 
    '0X0X' AS [C1], 
    [Extent1].[A_PAR_ParentId] AS [A_PAR_ParentId], 
    [Extent1].[A_PAR_Data] AS [A_PAR_Data], 
    [Extent2].[B_CHL_ChildId] AS [B_CHL_ChildId], 
    [Extent2].[B_CHL_ChildData] AS [B_CHL_ChildData] 
    FROM [dbo].[A_PARENT] AS [Extent1] 
    INNER JOIN [dbo].[B_CHILD] AS [Extent2] ON [Extent1].[A_PAR_ParentId] = [Extent2].[A_PAR_ParentId] 

クエリでのみ正しくないものは結合述語である - そのようながありません:私は子供のすべてを取得しようとしたとき、私はEFは、このようなクエリを生成するので、SQLエラーになってしまうのでテーブルB_CHILDの列A_PAR_ParentId

EntityFrameworkでエンティティのプライマリキーを使用して、継承チェーンを構築する際に外部キーとして使用するにはどうすればよいですか? DB内のすべてのテーブルがこのパターンを使用しているため(型/テーブルが継承されている場合、プライマリキーは親のプライマリキーへの外部キーであり、コンポジットキーは存在しません)すべて)。たぶん私は、PKがFKでもナビゲーションプロパティなしであることをEFに伝える方法を探しています。

--edit:より多くのコード

モデルは非常に単純です:

[ModulePrefix("A"), TablePrefix("PAR")] 
    public class Parent 
    { 
     public Guid ParentId { get; set; } 
     public string Data { get; set; } 
    } 

    [ModulePrefix("B"), TablePrefix("CHL")] 
    public class Child : Parent 
    { 
     public Guid ChildId { get; set; } 
     public string ChildData { get; set; } 
    } 

と設定:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      base.OnModelCreating(modelBuilder); 
      modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); 

      modelBuilder.Types() 
       .Where(type => !type.GetCustomAttributes(false).OfType<TableAttribute>().Any() && type.GetCustomAttributes(false).OfType<ModulePrefixAttribute>().Any()) 
       .Configure(config => config.ToTable(
        ComposeDbName(GetModulePrefix(config.ClrType), 
        CamelCaseToUnderscore(GetClassName(config.ClrType)).ToUpper()) 
        )); 

      modelBuilder.Properties() 
       .Where(property => property.DeclaringType.GetCustomAttributes(false).OfType<TablePrefixAttribute>().Any() && property.DeclaringType == property.ReflectedType) 
       .Configure(config => config.HasColumnName(ComposeDbName(
        GetModulePrefix(config.ClrPropertyInfo.DeclaringType), 
        GetTablePrefix(config.ClrPropertyInfo.DeclaringType), 
        config.ClrPropertyInfo.Name 
        ))); 
      modelBuilder.Properties() 
       .Where(property => property.Name == property.DeclaringType.Name + "Id" && property.ReflectedType == property.DeclaringType) 
       .Configure(config => config.IsKey()); 

      modelBuilder.Properties() 
       .Where(property => property.PropertyType.IsClass || Nullable.GetUnderlyingType(property.PropertyType) != null) 
       .Configure(config => config.IsOptional()); 
     } 

列/テーブル名で遊んでいくつかのより多くの民間の方法があります。 。カラム/テーブル名がうまく解決されているように見えるので、この時点では重要ではないと思います。

+0

上記のdbテーブルに関連するコードファーストモデル/構成を見てみましょう。 –

+0

質問にいくつかのコードを追加しました。 –

+0

'Child.ChildId'フィールドで問題が発生しています。 –

答えて

0

タイプ/テーブルが継承されている場合=>主キーは、親の基本キーEF TPTの継承マッピングがどのように動作するかこれは正確に

への外部キー、ここではありませんので、競合です。

問題はクラスのChildIdプロパティです。 ChildParentを継承しているため、ParentIdプロパティも継承され、不正なTPTマッピングが発生します。それを削除し、基本クラス定義のプロパティをPK(およびFK)として使用する必要があります。派生テーブルに別の名前を付けるだけです。

PKプロパティの名前としてIdを使用して、別の名前を簡単に関連付けることをお勧めします。あなたのほかに2つの新しいプライベートヘルパーを使用しています

modelBuilder.Types() 
    .Where(type => !type.GetCustomAttributes(false).OfType<TableAttribute>().Any() && type.GetCustomAttributes(false).OfType<ModulePrefixAttribute>().Any()) 
    .Configure(config => config.ToTable(GetTableName(config.ClrType))); 

modelBuilder.Properties() 
    .Where(property => property.Name != "Id" && property.DeclaringType.GetCustomAttributes(false).OfType<TablePrefixAttribute>().Any() && property.DeclaringType == property.ReflectedType) 
    .Configure(config => config.HasColumnName(GetColumnName(config.ClrPropertyInfo.DeclaringType, config.ClrPropertyInfo.Name))); 

modelBuilder.Properties() 
    .Where(property => property.Name == "Id" && property.DeclaringType.GetCustomAttributes(false).OfType<TablePrefixAttribute>().Any()) 
    .Configure(config => config.IsKey().HasColumnName(GetColumnName(config.ClrPropertyInfo.ReflectedType, "Id"))); 

:その規則に基づいて

[ModulePrefix("A"), TablePrefix("PAR")] 
public class Parent 
{ 
    public Guid Id { get; set; } 
    public string Data { get; set; } 
} 

[ModulePrefix("B"), TablePrefix("CHL")] 
public class Child : Parent 
{ 
    public string ChildData { get; set; } 
} 

と設定:だからここ

は修正モデルは次のようになります方法です

static string GetTableName(Type entityType) 
{ 
    return ComposeDbName(
     GetModulePrefix(entityType), 
     CamelCaseToUnderscore(GetClassName(entityType)).ToUpper() 
    ); 
} 

static string GetColumnName(Type entityType, string propertyName) 
{ 
    return ComposeDbName(
     GetModulePrefix(entityType), 
     GetTablePrefix(entityType), 
     propertyName == "Id" ? GetClassName(entityType) + "Id" : propertyName 
    ); 
} 

これは、従来通り、これと同等のものを構築することです。

modelBuilder.Entity<Parent>().ToTable("A_PARENT"); 
modelBuilder.Entity<Parent>().Property(e => e.Id).HasColumnName("A_PAR_ParentId"); 
modelBuilder.Entity<Parent>().HasKey(e => e.Id); 
modelBuilder.Entity<Parent>().Property(e => e.Data).HasColumnName("A_PAR_Data"); 

modelBuilder.Entity<Child>().ToTable("B_CHILD"); 
modelBuilder.Entity<Child>().Property(e => e.Id).HasColumnName("B_CHL_ChildId"); 
modelBuilder.Entity<Child>().HasKey(e => e.Id); 
modelBuilder.Entity<Child>().Property(e => e.ChildData).HasColumnName("B_CHL_ChildData"); 
+0

子テーブルのプライマリ/外部キー名が親のプライマリキーと同じ名前になっていると仮定していませんか? –

+0

提案された設定は、データベーステーブルのように正確な列名を生成します - 'A_PAR_ParentId'と' B_CHL_ChildId' –

+0

統一されたPK **プロパティ名**を(クラス内で)使用し、各テーブルは規約に基づいています。 –

関連する問題