Was bedeutet das Hauptende einer Assoziation in einer 1: 1-Beziehung im Entity-Framework?

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;}
}

Ich habe versucht, dies in Entity Framework zu tun, als ich den Fehler bekam:

Das Hauptende einer Zuordnung zwischen den Typen 'ConsoleApplication5.Boo' und 'ConsoleApplication5.Foo' kann nicht ermittelt werden. Das Hauptende dieser Zuordnung muss explizit mithilfe der API für fließende Beziehungen oder mithilfe von Datenanmerkungen konfiguriert werden.

Ich habe Fragen zu StackOverflow mit einer Lösung für diesen Fehler gesehen, möchte aber verstehen, was der Begriff "Hauptende" bedeutet.

Taher Chhabrawala
quelle
Siehe docs.microsoft.com/en-us/ef/core/modeling/relationships für eine Erklärung der Begriffe
DeepSpace101

Antworten:

378

In einer Eins-zu-Eins-Beziehung muss ein Ende prinzipiell und das zweite Ende abhängig sein. Das Hauptende ist dasjenige, das zuerst eingefügt wird und das ohne das abhängige existieren kann. Das abhängige Ende muss nach dem Principal eingefügt werden, da es einen Fremdschlüssel für den Principal hat.

Im Falle eines Entity Frameworks muss FK in Dependent auch dessen PK sein. In Ihrem Fall sollten Sie also Folgendes verwenden:

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

Oder fließendes Mapping

modelBuilder.Entity<Foo>()
            .HasOptional(f => f.Boo)
            .WithRequired(s => s.Foo);
Ladislav Mrnka
quelle
6
@Ladislav, ich muss zwei unabhängige Tabellen erstellen, die beide einen optionalen Verweis aufeinander haben (eins zu eins). Ich möchte, dass beide ihre eigenen PKs haben. Wie ist das möglich? Ich habe eine separate Frage gestellt .
Shimmy Weitzhandler
10
Sie haben keine Ahnung, wie viele Stunden es gedauert hat, eine Antwort auf diese Frage zu finden - ms Dokumentation ist POOOOOOP ty.
Gangelo
1
Beachten Sie, dass Sie möglicherweise mithilfe von System.ComponentModel.DataAnnotations.Schema hinzufügen müssen. ForeignKey in VS2012 zu bekommen
stuartdotnet
2
Bedeutet das, dass Foodas dann der Auftraggeber ist?
bflemi3
8
@ bflemi3 Sie sind richtig Booist die abhängige, benötigt eine Foo, und bekommt den Fremdschlüssel. Fooist der Auftraggeber und kann ohne a existieren Boo.
Colin
182

Sie können auch das [Required]Datenanmerkungsattribut verwenden, um dies zu lösen:

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; }
}

Fooist erforderlich für Boo.

Leniel Maccaferri
quelle
Dies war für meinen folgenden Code korrekt, in dem ich eine Zuordnung zwischen den beiden als separate Entität wollte. Öffentliche Klasse Organisation {public int Id {get; einstellen; }} Benutzer der öffentlichen Klasse {public int Id {get; einstellen; }} öffentliche Klasse UserGroup {[Key] public int Id {get; einstellen; } [Erforderlich] öffentliche virtuelle Organisation Organisation {get; einstellen; } [Erforderlich] öffentlicher virtueller Benutzer Benutzer {get; einstellen; }}
AndyM
Ich benutze Oracle und keine der fließenden APIs hat für mich funktioniert. Dank bro. So einfach.
CameronP
11
Beachten Sie, dass bei Verwendung dieser Lösung Validierungsausnahmen auftreten, wenn Sie versuchen, eine Boosoeben aus der Datenbank abgerufene Version zu aktualisieren , es sei denn, Sie lösen zuerst das verzögerte Laden der FooEigenschaft aus. entityframework.codeplex.com/SourceControl/network/forks/…
NathanAldenSr
2
sollte dann nicht Boo Boovirtuell sein?
Simon_Weaver
1
@ NathanAldenSr der Link ist jetzt schlecht, wie machst du diese Änderung?
CamHart
9

Dies bezieht sich auf die Antwort von @Ladislav Mrnka zur Verwendung einer fließenden API zum Konfigurieren einer Eins-zu-Eins-Beziehung.

Hatte eine Situation, in der FK of dependent must be it's PKes nicht machbar war.

ZB hat Fooschon eine Eins-zu-Viele-Beziehung zu 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;
}

Jetzt mussten wir eine weitere Eins-zu-Eins-Beziehung zwischen Foo und Bar hinzufügen.

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;
}

So spezifizieren Sie eine Eins-zu-Eins-Beziehung mit fließender API:

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

Beachten Sie, dass beim Hinzufügen PrimaryBarIdentfernt werden muss, da wir dies durch eine flüssige API angeben.

Beachten Sie auch, dass der Methodenname [WithOptionalPrincipal()][1]irgendwie ironisch ist. In diesem Fall ist Principal Bar. Die Beschreibung von WithOptionalDependent () auf msdn macht es klarer.

Sudarshan_SMD
quelle
2
Was ist, wenn Sie die Immobilie tatsächlich wollenPrimaryBarId ? Das ist lächerlich für mich. Wenn ich die Eigenschaft hinzufüge und sage, dass es sich um den Fremdschlüssel handelt, wird eine Fehlermeldung angezeigt. Aber wenn ich die Eigenschaft nicht habe, wird EF sie trotzdem erstellen. Was ist der Unterschied?
Chris Pratt
1
@ChrisPratt Dies klingt möglicherweise nicht vernünftig. Ich bin nach Spur und Irrtum zu diesen Lösungen gekommen. Konnte keine Eins-zu-Eins-Zuordnung konfigurieren, wenn ich eine PrimayBarIdEigenschaft in einer FooEntität hatte. Wahrscheinlich die gleiche Lösung, die Sie versucht haben. Einschränkungen in EF vielleicht?
Sudarshan_SMD
3
Ja, ist es. Ich habe herausgefunden, dass EF bis heute keine eindeutigen Indizes implementiert hat. Daher besteht die einzige Möglichkeit, eine Eins-zu-Eins-Zuordnung vorzunehmen, darin, den Primärschlüssel des Hauptendes als Primärschlüssel des abhängigen Endes zu verwenden, da ein Primärschlüssel von Natur aus eindeutig ist. Mit anderen Worten, sie haben es zur Hälfte implementiert und eine Verknüpfung verwendet, die vorschreibt, dass Ihre Tabellen nicht standardisiert gestaltet werden müssen.
Chris Pratt