エンティティフレームワークの1対1の関係における関連付けの主な終わりは何を意味します


269
public class Foo
{
    public string FooId{get;set;}
    public Boo Boo{get;set;}
}


public class Boo
{
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

エラーが発生したとき、私はエンティティフレームワークでこれをやろうとしていました:

タイプ 'ConsoleApplication5.Boo'と 'ConsoleApplication5.Foo'の間の関連付けの主な終了を判別できません。この関連付けの主要な端は、リレーションシップFluent APIまたはデータアノテーションを使用して明示的に構成する必要があります。

StackOverflowでこのエラーの解決策に関する質問を見てきましたが、「プリンシパルエンド」という用語の意味を理解したいと思います。


用語の説明については、
docs.microsoft.com / en

回答:


378

1対1の関係では、一方の端が主で、もう一方の端が従属でなければなりません。プリンシパルエンドは、最初に挿入され、依存するエンドなしで存在できるエンドです。依存エンドは、プリンシパルへの外部キーがあるため、プリンシパルの後に挿入する必要があるエンドです。

エンティティフレームワークの場合、依存関係のFKはそのPKでもある必要があるため、次のコードを使用する必要があります。

public class Boo
{
    [Key, ForeignKey("Foo")]
    public string BooId{get;set;}
    public Foo Foo{get;set;}
}

または流暢なマッピング

modelBuilder.Entity<Foo>()
            .HasOptional(f => f.Boo)
            .WithRequired(s => s.Foo);

6
@Ladislav、お互いにオプションの参照(1対1)を持つ2つの独立したテーブルを作成する必要があります。両方にそれぞれ独自のPKを持たせたいのですが、これはどのように可能ですか?別の質問を投稿しました。
Shimmy Weitzhandler

10
これに対する答えを見つけるのに何時間かかったのか、あなたにはわかりません。
ガンゲロ2013年

1
System.ComponentModel.DataAnnotations.Schemaを使用して追加する必要がある場合があることに注意してください。VS2012でForeignKeyを取得するには
stuartdotnet

2
それはそれFooがプリンシパルであることを意味しますか?
bflemi3 2013年

8
正しい@ bflemi3 Booは依存型であり、を必要Fooとし、外部キーを取得します。Fooはプリンシパルであり、なしでも存在できますBoo
コリン

182

[Required]データアノテーション属性を使用してこれを解決することもできます。

public class Foo
{
    public string FooId { get; set; }

    public Boo Boo { get; set; }
}

public class Boo
{
    public string BooId { get; set; }

    [Required]
    public Foo Foo {get; set; }
}

Fooには必須ですBoo


これは、次のコードでは正しいものでした。2つの間のマップを別個のエンティティーとして公開しました。パブリッククラスOrganization {public int Id {get; セットする; }} public class user {public int Id {get; セットする; }} public class UserGroup {[Key] public int Id {get; セットする; } [必須]パブリック仮想組織Organization {get; セットする; } [必須]パブリック仮想ユーザーUser {get; セットする; }}
AndyM 2014

私はOracleを使用しており、流暢なAPIはどれも機能しません。ありがとう兄貴。とても簡単。
CameronP 2014

11
このソリューションを使用する場合Boo、最初にFooプロパティのレイジーロードをトリガーしない限り、データベースから取得したを更新しようとすると、検証例外が発生することに注意してください。entityframework.codeplex.com/SourceControl/network/forks/...
NathanAldenSr

2
Boo Booじゃあ仮想にすべきじゃないの?
Simon_Weaver 2017年

1
@NathanAldenSrリンクが悪いのですが、どのように変更するのですか?
CamHart

9

これは、1対1の関係を構成するためのFluent APIの使用に関する@Ladislav Mrnkaの回答を参照しています。

持つことFK of dependent must be it's PKが実現不可能であった状況を持っていました。

たとえば、とFoo既に1 対多の関係がありBarます。

public class Foo {
   public Guid FooId;
   public virtual ICollection<> Bars; 
}
public class Bar {
   //PK
   public Guid BarId;
   //FK to Foo
   public Guid FooId;
   public virtual Foo Foo;
}

ここで、FooとBarの間に1対1の関係をもう1つ追加する必要がありました。

public class Foo {
   public Guid FooId;
   public Guid PrimaryBarId;// needs to be removed(from entity),as we specify it in fluent api
   public virtual Bar PrimaryBar;
   public virtual ICollection<> Bars;
}
public class Bar {
   public Guid BarId;
   public Guid FooId;
   public virtual Foo PrimaryBarOfFoo;
   public virtual Foo Foo;
}

Fluent APIを使用して1対1の関係を指定する方法は次のとおりです。

modelBuilder.Entity<Bar>()
            .HasOptional(p => p.PrimaryBarOfFoo)
            .WithOptionalPrincipal(o => o.PrimaryBar)
            .Map(x => x.MapKey("PrimaryBarId"));

PrimaryBarIdFluent APIを使用して指定するため、追加は削除する必要があることに注意してください。

また、メソッド名[WithOptionalPrincipal()][1]は一種の皮肉なことに注意してください。この場合、プリンシパルはBarです。msdnのWithOptionalDependent()の説明は、それをより明確にします。


2
あなたが実際にプロパティが必要な場合はどうなりPrimaryBarIdますか?これは私にはばかげています。プロパティを追加し、それが外部キーであると言うと、エラーが発生します。しかし、私がそのプロパティを持っていない場合、EFはとにかくそれを作成します。違いは何ですか?
クリスプラット

1
@ChrisPrattこれは妥当に聞こえないかもしれません。試行錯誤の末、私はこの解決策にたどり着きました。エンティティにPrimayBarIdプロパティがあると、1対1のマッピングを構成できませんでしたFoo。おそらくあなたが試したのと同じ解決策です。EFの制限?
Sudarshan_SMD 2017年

3
そうですよ。今日までのEFが一意のインデックスを実装したことがないことがわかりました。その結果、1対1をマップするために利用できる唯一の方法は、主キーの性質が一意であるため、主エンドの主キーを従属エンドの主キーとして使用することです。言い換えれば、彼らはそれを半分実装し、あなたのテーブルが非標準的な方法で設計されなければならないことを指示する近道を取りました。
クリスプラット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.