EntityFramework複合キーとのコア関係

asp.net asp.net-core c# entity-framework entity-framework-core

質問

次のデータベーステーブルを検討してください。残念ながら、テーブルを変更することはできません。

データベーススキーマ

Housesは、 Idという名前の自動インクリメントIDフィールド、 NameというName文字列フィールド、およびAreaIdというNameの整数フィールドがAreaIdます。後者はAreasテーブルへの外部キーではありません。

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

注: Houseに複数のAreaのはなぜですか? Houseは複数のArea's, it only has one持っておらずArea's, it only has oneエリアArea's, it only has oneいません. The Area`sテーブルには、特定の行が複数の翻訳を持っているだろうことを意味し、複合キーを持っています。例:エリアID 5の英語のLangId 5とスペイン語のLangId 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が出力ウィンドウに生成され、結果として得られるListに、Areasと誤って一致した住宅が含まれます。

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は[a].[AreaId][h].[Id] [h].[AreaId]ません。この関係をEFでどのように表現できますか?

受け入れられた回答

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

主な設計上の欠陥は、翻訳が追加されるときに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は残りを推論します)。

modelBuilder.Entity<AreaTranslation>()
            .HasKey(a => new { a.AreaId, a.LanguageId });

あなたはArea真にそこの物理的な領域を真に表していることが分かります。 Houseは当然1つのArea 、このAreaの奇妙なコレクションではなく、どうにかして1つのエリアとみなされる必要があります。さまざまな言語がAreaTranslationジャンクションクラスにAreaTranslationます。 1つのAreaが1つのCountry属すると仮定します。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ