6

これは、精通したEFユーザーにとっては簡単な質問です。

テーブル間の関係がどのように見えるかについて、次のスキーマ(頭の中に)があります。

[FooBar]      [Foo]          [Bar]

FooId PK,FK   Id PK          Id PK
BarId PK,FK   BarId FK       Name
IsRead        Name           Description
              Description    

ただし、EFコードを使用してスキーマを生成しようとすると、最初に、エンティティ間の関係を解釈したとおりに解釈できず(テーブルに外部キーFooIdを追加)、ブリッジテーブル[bar]を完全に作成できません。[FooBar]

誰かがEF4コードを使用して上記のスキーマを実現する方法について私を案内してくれるなら、最初にそれをいただければ幸いです。ソリューションにPOCOモデルの属性が含まれるか、流暢な構成であるか、両方のハイブリッドであるかは、目的のデータベーススキーマが作成されている限り、それほど重要ではありません。


POCOモデル:

public class Foo
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }
    public int BarId { get; set; }

    public Bar Bar { get; set; } /* bar entity */

    public virtual ICollection<Bar> BridgedBars { get; set; }

    public Foo()
    {
        Bars = new List<Bar>();
    }
}

public class Bar
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
    public virtual ICollection<Foo> BridgedFoos { get; set; }

    public Bar()
    {
        Foos = new List<Foo>();
        BridgedFoos = new List<Foo>();
    }
}

public class FooBar
{
    public int FooId { get; set; }
    public int BarId { get; set; }

    public virtual Foo Foo { get; set; }
    public virtual Bar Bar { get; set; }

    public bool IsRead { get; set; }
}
4

1 に答える 1

9

モデルは実際に、で定義された関係に属する外部キーFooIdBar作成しFoo.BrideBarsます。EFは、このナビゲーションプロパティをのプロパティの1つに関連付けません。これは、ICollection<Foo>プロパティBar2つあり、EFはどちらが正しいペアであるかを一意に判別できないためです。その結果Foo.BrideBars、もう一方の端にナビゲーションプロパティがない場合の関係が作成されます。いわば、Bar.Foo外部キーを引き起こす目に見えないプロパティがあります。

モデルにマップするデータベーススキーマは、実際には多対多の関係を表すのではなく、中間の「ブリッジ」エンティティとの2つの1対多の関係を表しますFooBar。正しい関係を定義するには、ナビゲーションプロパティでこのクラスを使用する必要があります。次のようになります。

public class Foo
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public int BarId { get; set; }
    public Bar Bar { get; set; }

    public virtual ICollection<FooBar> FooBars { get; set; }
}

public class Bar
{
    public int Id { get; set; }
    public string Text { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
    public virtual ICollection<FooBar> FooBars { get; set; }

}

public class FooBar
{
    [Key, Column(Order = 0)]
    public int FooId { get; set; }
    [Key, Column(Order = 1)]
    public int BarId { get; set; }

    public virtual Foo Foo { get; set; }
    public virtual Bar Bar { get; set; }

    public bool IsRead { get; set; }
}

このモデルの命名規則により、正しい関係が検出されます。プロパティ名が規則(プロパティなしおよびプロパティなし)を満たしていないため、エンティティに対してのみFooBarキーを明示的に定義する必要があります。このモデルでは、で複合キーを使用するのが理にかなっています。IdFooBarIdFooBar

Fooおそらく、実際のクラスとプロパティには名前とがありませんBar。本名が規則に従わない場合は、アノテーションまたはFluentAPIを使用して関係を指定する必要があります。

modelBuilder.Entity<Foo>()
    .HasRequired(f => f.Bar)
    .WithMany(b => b.Foos)
    .HasForeignKey(f => f.BarId);

modelBuilder.Entity<FooBar>()
    .HasKey(fb => new { fb.FooId, fb.BarId }); // replaces the [Key] annotations

modelBuilder.Entity<FooBar>()
    .HasRequired(fb => fb.Foo)
    .WithMany(f => f.FooBars)
    .HasForeignKey(fb => fb.FooId);

modelBuilder.Entity<FooBar>()
    .HasRequired(fb => fb.Bar)
    .WithMany(b => b.FooBars)
    .HasForeignKey(fb => fb.BarId);

データベーススキーマでは、FooBarテーブルに複合主キーがあります。

[FooBar]       [Foo]          [Bar]

FooId PK,FK    Id PK          Id PK
BarId PK,FK    BarId FK       Name
IsRead         Name           Description
               Description    

FooBarただし、EFモデルのすべてのエンティティには、データベーステーブルの主キーにマップされるキープロパティ(単一または複合)が定義されている必要があるため、PKを含める必要があります。

この質問(関連付けテーブルに追加のフィールドを使用して、最初にコードを作成します)では、このようなタイプの関係を操作する方法について詳しく説明します。(これを「ペイロードとの多対多の関係」と呼ぶこともあります(IsReadプロパティは、サンプルモデルでは「ペイロード」です)が、実際には多対多ではありません。)

于 2012-06-03T12:06:48.120 に答える