Definieren und Verwalten von Beziehungen (Entity Framework)

Im Entity Framework kann sich eine Entität durch eine Zuordnung auf andere Entitäten beziehen. Diese Beziehung zwischen Entitäten wird durch das Association-Element im konzeptionellen Modell definiert. Jede Beziehung enthält zwei Enden, die den Entitätstyp und die Multiplizität des Typs (eins, Null-oder-eins oder n) beschreiben. Die Beziehung wird möglicherweise von einer referenziellen Einschränkung geregelt, die beschreibt, welches Ende der Beziehung die Prinzipalrolle und welches die abhängige Rolle ist.

Ab .NET Framework Version 4 können Sie Fremdschlüssel in das konzeptionelle Modell aufnehmen. Die Option Fremdschlüsselspalten in das Modell einbeziehen des Entity Data Model -Assistenten ist standardmäßig aktiviert. Wenn diese Option aktiviert wird, verfügen die generierten Entitätsobjekte über skalare Eigenschaften, die Fremdschlüsselspalten zugeordnet sind. Wenn Fremdschlüsseleigenschaften einbezogen wurden, können Sie durch das Ändern des Fremdschlüsselwerts für ein abhängiges Objekt eine Beziehung erstellen oder ändern. Diese Art von Zuordnung wird Fremdschlüsselzuordnung genannt.

Wenn Fremdschlüsselspalten nicht im konzeptionellen Modell enthalten sind, werden die Zuordnungsinformationen als unabhängiges Objekt verwaltet. Beziehungen werden durch Objektverweise und nicht durch Fremdschlüsseleigenschaften verfolgt und als ObjectStateEntry-Objekt im ObjectStateManager dargestellt. Dieser Typ von Zuordnung wird als unabhängige Zuordnung bezeichnet. Die gängigste Methode, eine unabhängige Zuordnung zu ändern, besteht im Ändern der Navigationseigenschaften, die für jede an der Zuordnung beteiligte Entität generiert werden.

In beiden Typen von Zuordnungen kann jedes Objekt über eine Navigationseigenschaft für jede Beziehung verfügen, an der es beteiligt ist. Mit den Navigationseigenschaften können Sie Beziehungen in beiden Richtungen navigieren und verwalten, wobei entweder ein Verweisobjekt zurückgegeben wird, wenn die Multiplizität eins oder Null ist, oder eine Auflistung von Objekten, wenn die Multiplizität n ist.

Mischen von Beziehungen

Sie können wahlweise einen oder beide Zuordnungstypen im Modell verwenden. Wenn Sie jedoch eine Tabelle einbeziehen, die nur Fremdschlüssel (auch reine Verknüpfungstabelle genannt) im Modell enthält, wird selbst dann eine unabhängige Zuordnung zum Verwalten der reinen m:n-Beziehung verwendet, wenn Sie angegeben haben, dass im Modell eine Fremdschlüsselzuordnung verwendet werden soll. Der Entity Data Model -Assistent erstellt keine Entität, die einer reinen Verknüpfungstabelle zugeordnet ist.

Erstellen und Ändern von Beziehungen

Im Entity Framework können Sie Beziehungen auf verschiedene Weise erstellen und ändern.

  1. Durch das Zuweisen einer Navigationseigenschaft zu einem neuen Objekt. Der folgende Code erstellt eine Beziehung zwischen der order-Entität und der customer-Entität. Wenn die Objekte an den Objektkontext angefügt werden, wird der customer.Orders-Auflistung das order-Objekt hinzugefügt, und die entsprechende Fremdschlüsseleigenschaft für das order-Objekt wird auf den Wert der Schlüsseleigenschaft des Customer-Objekts festgelegt:

    order.Customer = customer 
    
  2. Durch das Löschen eines Objekts aus einer Entitätsauflistung oder das Hinzufügen eines Objekts zu einer Entitätsauflistung. Sie können beispielsweise mit der Add-Methode ein Objekt vom Typ Order der customer.Orders-Auflistung hinzufügen. Durch diesen Vorgang wird eine Beziehung zwischen einem bestimmten order-Objekt und einem bestimmten customer-Objekt erstellt. Wenn die Objekte dem Objektkontext angefügt werden, werden der Kundenverweis und die Fremdschlüsseleigenschaft für das order-Objekt auf das entsprechende customer-Objekt festgelegt:

    customer.Orders.Add(order)
    
  3. In Fremdschlüsselzuordnungen können Sie einer Fremdschlüsseleigenschaft wie im folgenden Beispiel einen neuen Wert zuweisen. Nachdem der Verweis hinzugefügt worden ist, wird die Verweisnavigationseigenschaft erst mit den Schlüsselwerten eines neuen Objekts synchronisiert, wenn SaveChanges aufgerufen wird. Es findet keine Synchronisierung statt, da der Objektkontext erst dann permanente Schlüssel für hinzugefügte Objekte enthält, wenn diese gespeichert werden. Weitere Informationen finden Sie unter Arbeiten mit Entitätsschlüsseln (Entity Framework). Wenn neue Objekte vollständig synchronisiert werden müssen, sobald die Beziehung festgelegt wurde, verwenden Sie eine der beiden oben genannten Methoden.

    order.CustomerID = newCustomer.CustomerID 
    order.CustomerID = null
    
  4. Durch das Erstellen des Entitätsschlüssels für ein bestimmtes Objekt. Wenn ein Objekt mit diesem Schlüssel bereits im Objektkontext vorhanden ist, gibt die CreateEntityKey-Methode den EntityKey-Wert des vorhandenen Objekts zurück. Dieser Methode wird zur Sicherstellung der Abwärtskompatibilität mit .NET Framework 3.5 SP1 bereitgestellt.

    order.CustomerReference.EntityKey = ctx.CreateEntityKey("EntitySetName", newObject)
    

Wenn Sie die Beziehung der Objekte ändern, die mit einer der oben beschriebenen Methoden an den Objektkontext angefügt wurde, muss Entity Framework die Fremdschlüssel, Verweise und Auflistungen synchronisieren. Entity Framework verwaltet diese Synchronisierung für bestimmte Typen einschlägiger Objekte:

Wenn Sie POCO-Entitäten ohne Proxys verwenden, müssen Sie die DetectChanges-Methode aufrufen, um die verknüpften Objekte im Objektkontext zu synchronisieren. Wenn Sie mit nicht verbundenen Objekten arbeiten, müssen Sie die Synchronisierung manuell handhaben.

In den folgenden Beispielen wird gezeigt, wie die Fremdschlüsseleigenschaft und die Navigationseigenschaft verwendet werden, um die verknüpften Objekte zuzuordnen. Bei Fremdschlüsselzuordnungen können Sie beide Methoden verwenden, um Beziehungen zu erstellen oder zu ändern. Bei unabhängigen Zuordnungen können Sie die Fremdschlüsseleigenschaft nicht verwenden.

' The following example creates a new StudentGrade object and associates 
' the StudentGrade with the Course and Person by 
' setting the foreign key properties. 

Using context As New SchoolEntities()
    ' The database will generate the EnrollmentID. 
    ' To create the association between the Course and StudentGrade, 
    ' and the Student and the StudentGrade, set the foreign key property 
    ' to the ID of the principal. 
    Dim newStudentGrade = New StudentGrade With
    {
        .EnrollmentID = 0,
        .Grade = CDec(4.0),
        .CourseID = 4022,
        .StudentID = 17
    }

    ' Adding the new object to the context will synchronize 
    ' the references with the foreign keys on the newStudentGrade object. 
    context.StudentGrades.AddObject(newStudentGrade)

    ' You can access Course and Student objects on the newStudentGrade object
    ' without loading the references explicitly because
    ' the lazy loading option is set to true in the constructor of SchoolEntities.
    Console.WriteLine("Student ID {0}:", newStudentGrade.Person.PersonID)
    Console.WriteLine("Course ID {0}:", newStudentGrade.Course.CourseID)

    context.SaveChanges()
End Using

' The following example creates a new StudentGrade and associates 
' the StudentGrade with the Course and Person by 
' setting the navigation properties to the Course and Person objects that were returned 
' by the query. 
' You do not need to call AddObject() in order to add the grade object 
' to the context, because when you assign the reference 
' to the navigation property the objects on both ends get synchronized by the Entity Framework. 
' Note, that the Entity Framework will not synchronize the ends untill the SaveChanges method 
' is called if your objects do not meet the change tracking requirements. 
Using context = New SchoolEntities()
    Dim courseID = 4022
    Dim course = (From c In context.Courses
                 Where c.CourseID = courseID
                 Select c).First()

    Dim personID = 17
    Dim student = (From p In context.People
                  Where p.PersonID = personID
                  Select p).First()

    ' The database will generate the EnrollmentID. 
    ' Use the navigation properties to create the association between the objects. 
    Dim newStudentGrade = New StudentGrade With
    {
        .EnrollmentID = 0,
        .Grade = CDec(4.0),
        .Course = course,
        .Person = student
    }
    context.SaveChanges()
End Using
// The following example creates a new StudentGrade object and associates
// the StudentGrade with the Course and Person by
// setting the foreign key properties. 

using (SchoolEntities context = new SchoolEntities())
{
    StudentGrade newStudentGrade = new StudentGrade
    {
        // The database will generate the EnrollmentID.
        EnrollmentID = 0,
        Grade = 4.0M,
        // To create the association between the Course and StudentGrade, 
        // and the Student and the StudentGrade, set the foreign key property 
        // to the ID of the principal.
        CourseID = 4022,
        StudentID = 17,
    };

    // Adding the new object to the context will synchronize
    // the references with the foreign keys on the newStudentGrade object.
    context.StudentGrades.AddObject(newStudentGrade);

    // You can access Course and Student objects on the newStudentGrade object
    // without loading the references explicitly because
    // the lazy loading option is set to true in the constructor of SchoolEntities.
    Console.WriteLine("Student ID {0}:", newStudentGrade.Person.PersonID);
    Console.WriteLine("Course ID {0}:", newStudentGrade.Course.CourseID);
    
    context.SaveChanges();
}

// The following example creates a new StudentGrade and associates
// the StudentGrade with the Course and Person by
// setting the navigation properties to the Course and Person objects that were returned
// by the query. 
// You do not need to call AddObject() in order to add the grade object
// to the context, because when you assign the reference 
// to the navigation property the objects on both ends get synchronized by the Entity Framework.
// Note, that the Entity Framework will not synchronize the ends untill the SaveChanges method
// is called if your objects do not meet the change tracking requirements. 
using (var context = new SchoolEntities())
{
    int courseID = 4022;
    var course = (from c in context.Courses
                 where c.CourseID == courseID
                 select c).First();

    int personID = 17;
    var student = (from p in context.People
                  where p.PersonID == personID
                  select p).First();

    StudentGrade grade = new StudentGrade
    {
        // The database will generate the EnrollmentID.
        Grade = 4.0M,
        // Use the navigation properties to create the association between the objects.
        Course = course,
        Person = student
    };
    context.SaveChanges();
}

Zustandsänderung

Wenn Sie die Beziehung bei einer Fremdschlüsselzuordnung ändern, ändert sich der Zustand eines abhängigen Objekts mit dem Unchanged-Zustand in Modified.

In einer unabhängigen Beziehung wird der Zustand des abhängigen Objekts bei einer Änderung der Beziehung nicht geändert.

Verwalten der Parallelität

Sowohl in Fremdschlüsselzuordnungen als auch unabhängigen Zuordnungen basieren Parallelitätsüberprüfungen auf den Entitätsschlüsseln und anderen Entitätseigenschaften, die in der konzeptionellen Ebene definiert werden, indem das ConcurrencyMode-Attribut auf fixed festgelegt wird.

In einer unabhängigen Zuordnung wird die Parallelitätsüberprüfung der Beziehung immer für die Objekte an beiden Enden der Beziehung ausgeführt. Bei dieser Überprüfung werden die ursprünglichen Schlüsselwerte der verknüpften Enden überprüft. Wenn Sie die Beziehung ändern, während das Objekt vom Objektkontext getrennt ist, müssen Sie die ursprüngliche Beziehung (entweder durch erneutes Abfragen oder Eintragen der ursprünglichen Schlüsselwerte) neu erstellen, das Objekt an den Objektkontext anfügen und dann die entsprechenden Änderungen an der Beziehung in diesem Objektkontext vornehmen.

Arbeiten mit sich überlappenden Schlüsseln

Überlappende Schlüssel sind zusammengesetzte Schlüssel, wobei einige Eigenschaften eines Schlüssels auch Teil eines anderen Schlüssels der Entität sind. Unabhängige Zuordnungen können keine überlappenden Schlüssel enthalten. Um eine Fremdschlüsselzuordnung zu ändern, die überlappende Schlüssel enthält, empfiehlt es sich, die Fremdschlüsselwerte zu ändern, statt die Objektverweise zu verwenden.

Laden von verknüpften Objekten

Wenn Sie in einer Fremdschlüsselzuordnung ein verknüpftes Ende eines abhängigen Objekts laden, wird das verknüpfte Objekt auf der Grundlage des Fremdschlüsselwerts des abhängigen Elements geladen, der sich gerade im Arbeitsspeicher befindet:

// Get the order where currently AddressID = 1.  SalesOrderHeader order = context.SalesOrderHeaders.First(o=>o.SalesOrderID == orderId);

// Use BillToAddressID foreign key property 
// to change the association.  order.BillToAddressID = 2
order.AddressReference.Load();  

In einer unabhängigen Zuordnung wird das verknüpfte Ende eines abhängigen Objekts auf der Grundlage des Fremdschlüsselwerts abgefragt, der sich gerade in der Datenbank befindet. Wenn die Beziehung geändert wurde und die Verweiseigenschaft für das abhängige Objekt auf ein anderes Prinzipalobjekt zeigt, das in den Objektkontext geladen wurde, versucht Entity Framework , eine Beziehung zu erstellen, die der auf dem Client definierten Beziehung entspricht.

Überlegungen zu identifizierenden und nicht identifizierenden Beziehungen

Wenn ein Primärschlüssel der Prinzipalentität auch Teil des Primärschlüssels der abhängigen Entität ist, dann handelt es sich um eine identifizierende Beziehung. In einer identifizierenden Beziehung kann die abhängige Entität nicht ohne die Prinzipalentität existieren. Diese Einschränkung bedingt das folgende Verhalten in einer identifizierenden Beziehung:

  • Wenn das Prinzipalobjekt gelöscht wird, wird auch das abhängige Objekt gelöscht. Dieses Verhalten entspricht der Angabe von <OnDelete Action="Cascade" /> im Modell für die Beziehung.

  • Durch das Entfernen der Beziehung wird das abhängige Objekt gelöscht. Durch einen Aufruf der Remove-Methode für EntityCollection werden sowohl die Beziehung als auch das abhängige Objekt zum Löschen markiert.

  • Beim Erstellen eines neuen abhängigen Objekts muss das Prinzpalobjekt vor dem Aufruf von SaveChanges im Objektkontext oder in der Datenquelle vorhanden sein. Wenn das Prinzipalobjekt nicht vorhanden ist, wird eine Ausnahme des Typs InvalidOperationException ausgelöst.

Wenn eine nicht identifizierende Beziehung vorliegt und das Modell auf Fremdschlüsselzuordnungen basiert, wird beim Löschen des Prinzipalobjekts der Fremdschlüssel von abhängigen Elementen auf NULL festgelegt, sofern dieser auf NULL festlegbar ist. Bei abhängigen Objekten, die ohne Prinzipal nicht existieren können, müssen Sie die abhängigen Objekte manuell löschen oder den abhängigen Objekten ein neues Prinzipalobjekt zuweisen. Alternativ können Sie <OnDelete Action="Cascade" /> angeben, um sicherzustellen, dass abhängige Objekte gelöscht werden, wenn Sie das zugehörige Prinzipalobjekt löschen.

In diesem Abschnitt

Navigationseigenschaften

Gewusst wie: Verwenden der Fremdschlüsseleigenschaft, um Beziehungen zwischen Objekten zu ändern

Gewusst wie: Verwenden von EntityReference zum Ändern von Beziehungen zwischen Objekten (Entity Framework)

Gewusst wie: Ändern von Beziehungen zwischen POCO-Entitäten (Entity Framework)

Siehe auch

Aufgaben

Gewusst wie: Verwenden von EntityReference zum Ändern von Beziehungen zwischen Objekten (Entity Framework)
Gewusst wie: Verwenden der Fremdschlüsseleigenschaft, um Beziehungen zwischen Objekten zu ändern

Konzepte

Erstellen, Hinzufügen, Ändern und Löschen von Objekten (Entity Framework)
Arbeiten mit POCO-Entitäten (Entity Framework)