2016-05-05 15 views
1

Was ist die beste Vorgehensweise zum Erstellen von Beziehungen und Schnittstellen mit EF?Beziehungen, Schnittstellen und Entitätsframework

Ich habe eine Reihe von bestehenden TDD-Klassen und Schnittstellen und eine Voraussetzung, Entity Framework Code zuerst als ORM zu verwenden. Ich habe Erfahrung mit EF, bin aber unzufrieden mit der Definition von Eins-zu-Viele- und Viele-zu-Viele-Beziehungen.

Ich bin überrascht, dass dies nicht mehr dominant dokumentiert erscheint (vorausgesetzt, ich suche nicht nach der falschen Terminologie).

Zum Beispiel habe ich:

public interface IBar { 
     string BarValue { get; set; } 
} 
public class Bar : IBar { 
     string BarValue { get; set; } 
} 


public interface IFoo { 
     string FooValue { get; set; } 
     ICollection<IBar> Bars { get; set; } 
} 

public class Foo : IFoo { 

     public Foo() 
     { 
      Bars = new List<Bar>(); 
     } 
     public string FooValue { get; set; } 
     public virtual ICollection<IBar> Bars { get; set; } 
} 

und

public interface IBar { 
     string BarValue { get; set; } 
     ICollection<IFoo> Foos { get; set; } 
} 
public class Bar : IBar { 
     public Bar() 
     { 
      Foos = new List<Foo>(); 
     } 
     string BarValue { get; set; } 
     public virtual ICollection<IFoo> Foos { get; set; } 
} 


public interface IFoo { 
     string FooValue { get; set; } 
     ICollection<IBar> Bars { get; set; } 
} 

public class Foo : IFoo { 
     public Foo() 
     { 
      Bars = new List<Bar>(); 
     } 
     public string FooValue { get; set; } 
     public virtual ICollection<IBar> Bars { get; set; } 
} 

Ich bin nicht sicher, ob ich auf dem richtigen Weg bin hier, irgendwelche Gedanken bitte?

+0

EF unterstützt keine Schnittstellen. Es kann nichts mit etwas wie ICollection 'tun. Aber es ist nicht klar, was Sie in EF zuordnen möchten und was Sie von diesen Schnittstellen erwarten. –

Antwort

1

Ich bin sicher, Sie wissen schon, Bit, da es nicht in Ihrer Probe ist, so dachte ich, ich würde es erwähnen: Vergessen Sie nicht Ihre leeren Konstruktoren. EF Code verwendet diese zuerst, um Ihr Modell zu füllen.

Allerdings möchten Sie wahrscheinlich nicht, dass sie ausgesetzt sind, also machen Sie sie geschützt statt öffentlich. EF wird weiterhin einen geschützten Konstruktor sehen, aber keinen privaten Konstruktor.

Ihre 1 zu viele Beziehung sieht gut aus mir, obwohl wenn Sie lazy laden möchten, sollte es virtuell sein.

Mit Ihren vielen zu vielen, ist meine Präferenz, das verbindende Wesen zu definieren. Ich glaube, dass EF einen Join-Tisch hinter den Kulissen für Sie mit dem aufbauen wird, was Sie haben. Ich möchte jedoch meine Navigationseigenschaften einseitig halten, um mögliche Rekursionsprobleme zu vermeiden, die später die Daten analysieren.

Ich werde dies mit einigen Beispielen basierend auf Ihren Beispielen bearbeiten, sobald ich an einen Computer komme.

OK Hier ist ein Beispiel für eine zu viele ... Ich habe zu laufen, aber viele zu viele diesen Abend posten, aber das Muster ist ziemlich einfach zu erweitern:

public interface IBar 
{ 
    string barValue { get; }  // Values can sometimes be valuable in interfaces, see Foo's AddBar behavior. 
    void SetValue(string value); // Interfaces work best describing behavior, not structure. 
} 
public class Bar : IBar 
{ 
    public string barValue { get; private set; } 

    protected Bar() : this("") { } // EF 
    private Bar(string value)  // Private Constructor 
    { 
     barValue = value; 
    } 

    public static Bar Create(string value = "") // Factory 
    { 
     return new Bar(value); 
    } 
} 


public interface IFoo 
{ 
    void SetValue(string value); 
    void AddBar(IBar bar); 
} 

public class Foo : IFoo 
{ 
    // Our Properties... note that private set does not interfere with EF at all, and helps encapsulate. 
    public string fooValue { get; private set; } 
    public virtual ICollection<Bar> bars { get; private set; } 

    // Constructor for EF, protected since we probably dont want to ever use it ourselves. 
    protected Foo() : this("") { } 

    // Our internal constructor, we will expose a factory for creating new instances (better control). 
    private Foo(string value) 
    { 
     fooValue = value; 
     bars = new List<Bar>(); 
    } 

    // Our factory, great place to validate parameters, etc before even constructing the object. 
    public static Foo Create(string value = "") 
    { 
     return new Foo(value); 
    } 

    // Methods for controling Foo's properties: 
    public void SetValue(string value) { this.fooValue = value; } 
    public void AddBar(IBar bar) { this.bars.Add(Bar.Create(bar.value)); } // Leveraging Bar's factory 
} 

EDIT: ich ursprünglich mit es seit dem Beispiel hatte es, aber ich würde normalerweise keine Eigenschaften in der Schnittstelle angeben. Typischerweise sollte eine Schnittstelle als eine Beschreibung von Verhalten und nicht von Struktur betrachtet werden. Tatsächlich funktioniert Entity Frame work nicht mit den Interfaces of properties (öffentlichen virtuellen ICollection-Leisten), da er diesen Konstruktor haben muss, um ihn füllen zu können, und natürlich hat eine Schnittstelle keinen Konstruktor. Ich habe das Beispiel entsprechend aktualisiert und die Schnittstellen mehr verhaltensgesteuert gemacht. Ich werde heute Abend noch ein Beispiel von vielen zu vielen hinzufügen.

OK, hier ist das viele zu viele. Einige Highlights: Ich habe die Foo und Bar Interfaces zu einem zusammengefasst, da beide das selbe Verhalten hatten, das ist etwas generischer. Beachten Sie, dass Sie nicht direkt den ganzen Weg zu foo von einer Bar mit foobar durchqueren können (Sie erhalten im Wesentlichen eine Liste von Ids), dies verhindert, dass Sie in zirkuläre Referenzen laufen. Sie können jederzeit eine Liste der einen oder anderen auf jeder Seite hinzufügen und sie bei Bedarf manuell aus Ihrem Repository ausfüllen.

public interface IFooBar 
{ 
    string value { get; } 
    void SetValue(string value); 
    void AddFooBar(IFooBar item); 
} 


public class Bar : IFooBar 
{ 
    public string value { get; private set; } 
    public virtual ICollection<FooBar> foos { get; private set; } 

    protected Bar() : this("") { } 
    private Bar(string v) { 
     value = v; 
     foos = new List<FooBar>(); 
    } 

    public static Bar Create(string value = "") { return new Bar(value); } 

    public void SetValue(string value) { this.value = value; } 

    public void AddFooBar(IFooBar foo) { this.foos.Add(FooBar.Create(this.value, foo.value)); } 
} 

public class FooBar 
{ 
    // assuming fooValue and barValue are the keys for Foo and Bar. 
    public String fooValue { get; private set; } 
    public String barValue { get; private set; } 

    protected FooBar() { } 
    private FooBar(String foo, String bar) { 
     fooValue = foo; 
     barValue = bar; 
    } 

    public static FooBar Create(String fooValue, String barValue) { return new FooBar(fooValue, barValue); } 
} 


public class Foo : IFooBar 
{ 
    public string value { get; private set; } 
    public virtual ICollection<FooBar> bars { get; private set; } 

    protected Foo() : this("") { } 

    private Foo(string v) 
    { 
     value = v; 
     bars = new List<FooBar>(); 
    } 

    public static Foo Create(string value = "") { return new Foo(value); } 

    public void SetValue(string value) { this.value = value; } 

    public void AddFooBar(IFooBar bar) { this.bars.Add(FooBar.Create(this.value, bar.value)); } 
} 

Auch bedenken Sie, dass Namenskonventionen nicht verwendet wurden, so werden Sie entweder müssen fließend Karten (empfohlen), um dekorieren oder fügen Sie für EF die Schlüssel zu erkennen und die Beziehungen aufzubauen ...wenn sie Namen EF Konvention wurden unter Verwendung dieses teilweise vermieden werden könnte, aber Sie müssen noch eine Karte für FooBar Multi-Part-Taste wie hinzuzufügen:

public class FooBarMap: EntityTypeConfiguration<FooBar> 
{ 
    public FooBarMap() 
    { 
     HasKey(k => new { k.barValue, k.fooValue }); 
    } 
} 

und fügen Sie dann an Ihre Kontext-Konfigurationen.

Hoffe, dass hilft ... :)

+0

Oh, und ein weiterer Vorteil der Definition der Cross-Join-Entity ist, dass Sie jetzt zusätzliche Eigenschaften hinzufügen können, wie zum Beispiel, wann die Beziehung gebildet wurde, oder sogar zu einer effektiven Dating-Beziehung. –