4

次のデータベーステーブルを検討してください。残念ながら、テーブルは決して変更できません。EntityFramework複合キーのコアの関係

Database schema

HousesIdという名前の自動インクリメントIDフィールド、Nameという名前の文字列フィールドとAreaIdという名前の整数フィールドを持っています。後者はAreasテーブルの外部キーではありません。

Areasは、AreaId,CountryIdおよびLangIdからなる複合キーを持っています。同一のAreaIdの領域が存在する可能性がありますが、異なるCountryIdLangIdがあります。例:同じAreaIdの2つの行がありますが、異なるLangIdがあります。

注:なぜHouseに複数のAreaがあるのですか? A Houseには複数の値がありませんArea's, it only has oneエリア. Theエリアのテーブルに複合キーがあります。つまり、特定の行に複数の翻訳が含まれています。例:エリアID 5は、英語ではランゲッド5、スペイン語ではランゲッド3を持つ場合があります。

2つのテーブルは、次の2つのC#クラスで記述されています。

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

    [MaxLength(80)] 
    public string Name { get; set; } 

    public int? AreaId { get; set; } 

    [ForeignKey("AreaId")] 
    public List<Area> Areas { get; set; } 
} 

public class Area 
{ 
    public int AreaId { get; set; } 

    public int CountryId { get; set; } 

    public string LangId { get; set; } 

    public string Name { get; set; } 
} 

コンポジットキーは、ドキュメントに記載されているとおりに定義されています。

protected override void OnModelCreating(ModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Area>() 
     .HasKey(a => new { a.AreaId, a.CountryId, a.LangId }); 
} 

たとえば、データベース内のすべての住宅のリストをそれぞれの領域を含めて取得します。

_context.Houses.Include(h => h.Areas).ToList(); 

次のSQLが出力ウィンドウに生成され、結果のリストには、誤ってエリアに一致するハウスが含まれています。

SELECT [a].[AreaId], [a].[CountryId], [a].[LangId], [a].[Name] 
FROM [Areas] AS [a] 
WHERE EXISTS (
    SELECT 1 
    FROM [Houses] AS [h] 
    WHERE [a].[AreaId] = [h].[Id]) 
ORDER BY [a].[Id] 

あなたが見ることができるように、EntityFrameworkは[h].[Id]なく[h].[AreaId][a].[AreaId]に関するものです。 EFでこの関係をどう表現することができますか?

+0

複合キーに設定コードを表示できますか? – Sampath

+0

私は複合キーの設定を追加して質問を編集しました – giannoug

+0

私はそれが可能ではないと思います。奇妙なdbデザインbtw、たとえ非論理的でも - どのように1つの家がいくつかのエリアなどにあるとか。 –

答えて

9

これをEFで正しくマップすることはできません。 HouseAreaを参照するようにするには、外部キーはAreaの複合キーと同じフィールドで構成する必要があります。そうでない場合、EFはマッピングを受け入れません。回避策は、マッピングをスキップし、必要に応じてエンティティに手動で参加することですが、実際の問題は隠蔽されます。poor design

翻訳の追加時にAreaを複製する必要があるという設計上の主な欠陥があります。今質問は - そしていつもあります - 私の物理的なAreaエンティティを表すレコードはどれですか?リレーショナルデータベースの基本的な前提は、エンティティがユニークレコードで表されることです。あなたのデザインはその基本原則に違反しています。

残念ながら、表は決して変更できません。

まあ、となります!それをこのままにしておくことは、考慮すべきではありません。反りのあるリレーショナル・モデルで作業するべきではありません。スムーズなアプリケーション開発のためにはあまりにも重要です。

モデル、私はあなたの説明から、それを一緒につなぎすることができますように、おそらくこのようなものでなければなりません:

public class House 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int? AreaId { get; set; } 
    public Area Area { get; set; } 
} 

public class Area 
{ 
    public int Id { get; set; } 
    public int CountryId { get; set; } 
    public Country Country { get; set; } 
    public string Name { get; set; } // E.g. the name in a default language 
    public ICollection<AreaTranslation> AreaTranslations { get; set; } 
} 

public class AreaTranslation 
{ 
    public int AreaId { get; set; } 
    public int LanguageId { get; set; } 
    public string LocalizedName { get; set; } 
} 

public class Country 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class Language 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

このモデルのために使用すると、1つの明示的なマッピング命令を必要とする(EFは残りを推測します):

Areaは、実際にそこの物理的領域を真に表しています。 A Houseは今や自然に1つのAreaを持っていますが、何らかの理由で1つの領域とみなされるべきであるこの奇妙なコレクションAreaではありません。様々な言語がAreaTranslation接合クラスによって作用する。私はAreaが1つのCountryに属すると仮定します。

+1

詳細な回答ありがとう!私はデータベースを継承していますが、私の設計ではありません(私はデータベースアーキテクトではありませんが、いくつかの常識を使用することができます)。新しいスキーマのための私の立場を強化するため – giannoug

関連する問題