2012-06-02 10 views
6

Dies sollte eine einfache Frage für den versierten EF-Benutzer sein.Zuordnung viele zu viele Beziehung mit Fremdschlüssel Referenz

Ich habe das folgende Schema (in meinem Kopf), wie die Beziehungen zwischen den Tabellen aussehen sollten.

[FooBar]  [Foo]   [Bar] 

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

Obwohl, wenn ich zu versuchen erzeugen das Schema mit EF Code zunächst die Beziehungen zwischen den Entitäten zu interpretieren nicht, wie ich sie habe interpretiert (fügt Fremdschlüssel FooId zur [bar] Tabelle) und schlägt fehl um die [FooBar] Bridge-Tabelle vollständig zu erstellen.

Wenn mir jemand helfen könnte, das obige Schema mit dem EF4-Code zu erreichen, würde ich es begrüßen. Ob die Lösung mit Attributen auf meinen POCO-Modellen, mit fließenden Konfigurationen oder mit einem Hybrid aus beiden verbunden ist, spielt keine große Rolle - solange das gewünschte Datenbankschema erstellt wird.


POCO-Modelle:

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

Wie Sie Haben Sie eine Eigenschaft (IsRead) für die FooBar-Beziehung, die Sie wahrscheinlich aus dem Code setzen möchten, benötigen sowohl Foo als auch Bar die zugehörigen Sammlungen als FooBars. Sobald Sie Eigenschaften an beiden Enden (d. H. Die virtuellen Sammlungen in Foo und Bar) zu FooBar zuordnen, sollte EF die Beziehung korrekt erstellen. Verwenden Sie HasMany(). WithRequired(), um jede Klasse FooBar zuzuordnen. –

Antwort

8

Ihr Modell wird in der Tat einen Fremdschlüssel FooId im Bar schaffen, die auf die Beziehung von Foo.BrideBars definiert gehört. EF bezieht diese Navigationseigenschaft nicht auf eine der ICollection<Foo>-Eigenschaften in Bar, da es zwei von ihnen gibt, und EF kann nicht eindeutig bestimmen, welches das richtige Paar ist. Als Ergebnis wird eine Beziehung für Foo.BrideBars ohne eine Navigationseigenschaft auf der anderen Seite erstellt. So, es gibt eine unsichtbare Bar.Foo Eigenschaft, die den Fremdschlüssel verursacht.

Das Datenbankschema, das Sie einem Modell zuordnen möchten, stellt nicht wirklich eine Viele-zu-Viele-Beziehung dar, sondern zwei Eins-zu-Viele-Beziehungen mit der Zwischen- "Brücken" -Entität FooBar. Sie müssen diese Klasse in den Navigationseigenschaften verwenden, um die richtigen Beziehungen zu definieren. Es würde so aussehen:

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

Die korrekten Beziehungen werden durch Namenskonventionen in diesem Modell erkannt. Nur für die Entität FooBar ist es erforderlich, einen Schlüssel explizit zu definieren, da die Eigenschaftsnamen nicht den Konventionen entsprechen (keine Id und keine FooBarId-Eigenschaft). In diesem Modell ist es sinnvoll, in FooBar einen zusammengesetzten Schlüssel zu verwenden.

Ich denke, Ihre realen Klassen und Eigenschaften haben nicht den Namen Foo und Bar. Wenn Ihre wirklichen Namen die Konventionen nicht folgen müssen Sie möglicherweise die Beziehungen mit Anmerkungen angeben - oder mit Fluent API:

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

In Ihrem Datenbankschema der FooBar Tabelle einen zusammengesetzten Primärschlüssel haben:

[FooBar]  [Foo]   [Bar] 

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

Aber ein PK in FooBar ist erforderlich, da jede Entität in einem EF-Modell eine Schlüsseleigenschaft definiert haben muss - entweder Single oder Composite - die einem Primärschlüssel in der Datenbanktabelle zugeordnet wird.

In dieser Frage - Create code first, many to many, with additional fields in association table - sind mehr Details, wie man mit einer solchen Art von Beziehung arbeiten. (Manchmal nennen die Leute auch "Viele-zu-Viele-Beziehung mit Nutzlast" (die IsRead Eigenschaft ist die "Nutzlast" in Ihrem Beispielmodell), aber in Wirklichkeit ist es nicht viele-zu-viele.)

+0

genau das, was ich suchte und ja, einen zusammengesetzten Primärschlüssel auf 'FooBar' zu haben, war meine Absicht - nur vergessen zu erwähnen! Danke für die tolle Antwort und Erklärung! Sobald mein Profil * 15 Punkte * erreicht hat, werde ich sicherlich wiederkommen und abstimmen. – culturalanomoly

Verwandte Themen