Freigeben über


Beziehungen, Navigationseigenschaften und Fremdschlüssel

In diesem Artikel finden Sie eine Übersicht darüber, wie Entity Framework Beziehungen zwischen Entitäten verwaltet. Außerdem enthält es einige Anleitungen zum Zuordnen und Bearbeiten von Beziehungen.

Beziehungen in EF

In relationalen Datenbanken werden Beziehungen (auch als Zuordnungen bezeichnet) zwischen Tabellen über Fremdschlüssel definiert. Ein Fremdschlüssel (FK) ist eine Spalte oder Eine Kombination von Spalten, die zum Einrichten und Erzwingen einer Verknüpfung zwischen den Daten in zwei Tabellen verwendet wird. Es gibt im Allgemeinen drei Arten von Beziehungen: eins-zu-eins, eins-zu-viele und viele-zu-viele. In einer 1:n-Beziehung wird der Fremdschlüssel in der Tabelle definiert, die das viele Ende der Beziehung darstellt. Die m:n-Beziehung umfasst das Definieren einer dritten Tabelle (als Verknüpfungs- oder Join-Tabelle bezeichnet), deren Primärschlüssel aus den Fremdschlüsseln beider verknüpften Tabellen besteht. In einer 1:1-Beziehung fungiert der Primärschlüssel zusätzlich als Fremdschlüssel, und für beide Tabellen gibt es keine separate Fremdschlüsselspalte.

Die folgende Abbildung zeigt zwei Tabellen, die in einer Eins-zu-viele-Beziehung stehen. Die Tabelle "Kurs " ist die abhängige Tabelle, da sie die Spalte "DepartmentID " enthält, die sie mit der Tabelle "Abteilung " verknüpft.

Abteilungs- und Kurstabellen

In Entity Framework kann eine Entität über eine Zuordnung oder Beziehung mit anderen Entitäten verknüpft sein. Jede Beziehung enthält zwei Enden, die den Entitätstyp und die Multiplizität des Typs (eins, null-oder-eins, oder viele) für die beiden Entitäten in dieser Beziehung beschreiben. Die Beziehung kann durch eine referenzielle Einschränkung gesteuert werden, die beschreibt, welches Ende in der Beziehung eine Hauptrolle ist und welche eine abhängige Rolle ist.

Navigationseigenschaften bieten eine Möglichkeit zum Navigieren in einer Beziehung zwischen zwei Entitätstypen. Jedes Objekt kann eine Navigationseigenschaft für jede Beziehung aufweisen, an der es teilnimmt. Mithilfe von Navigationseigenschaften können Sie in beide Richtungen navigieren und Beziehungen verwalten, indem Sie entweder ein Referenzobjekt zurückgeben (wenn die Multiplikation entweder 1 oder Null oder 1 ist) oder eine Auflistung (wenn die Multiplikation viele ist). Sie können auch eine unidirektionale Navigation verwenden. In diesem Fall definieren Sie die Navigationseigenschaft nur für einen der Typen, die an der Beziehung teilnehmen, und nicht für beides.

Es wird empfohlen, Eigenschaften in das Modell einzuschließen, die Fremdschlüsseln in der Datenbank zugeordnet sind. Wenn Fremdschlüsseleigenschaften enthalten sind, können Sie eine Beziehung erstellen oder ändern, indem Sie den Fremdschlüsselwert für ein abhängiges Objekt ändern. Diese Art von Zuordnung wird als Fremdschlüsselzuordnung bezeichnet. Die Verwendung von Fremdschlüsseln ist noch wichtiger, wenn Sie mit getrennten Entitäten arbeiten. Beachten Sie, dass beim Arbeiten mit 1-zu-1- oder 1-zu-0..1-Beziehungen es keine separate Fremdschlüsselspalte gibt; die Primärschlüsseleigenschaft fungiert als Fremdschlüssel und ist immer im Modell enthalten.

Wenn Fremdschlüsselspalten nicht im Modell enthalten sind, werden die Zuordnungsinformationen als unabhängiges Objekt verwaltet. Beziehungen werden über Objektverweise anstelle von Fremdschlüsseleigenschaften nachverfolgt. Diese Art von Zuordnung wird als unabhängige Zuordnung bezeichnet. Die am häufigsten verwendete Methode zum Ändern einer unabhängigen Zuordnung besteht darin, die Navigationseigenschaften zu ändern, die für jede Entität generiert werden, die an der Zuordnung teilnimmt.

Sie können einen oder beide Arten von Zuordnungen in Ihrem Modell verwenden. Wenn Sie jedoch eine reine m:n-Beziehung haben, die von einer Verknüpfungstabelle verbunden ist, die nur Fremdschlüssel enthält, verwendet das EF eine unabhängige Zuordnung, um eine solche m:n-Beziehung zu managen.   

Die folgende Abbildung zeigt ein konzeptionelles Modell, das mit dem Entity Framework-Designer erstellt wurde. Das Modell enthält zwei Entitäten, die an einer Eins-zu-Viele-Beziehung teilnehmen. Beide Entitäten weisen Navigationseigenschaften auf. Kurs ist die abhängige Entität und hat die Fremdschlüssel-Eigenschaft "DepartmentID" definiert.

Abteilungs- und Kurstabellen mit Navigationseigenschaften

Der folgende Codeausschnitt zeigt dasselbe Modell, das mit Code First erstellt wurde.

public class Course
{
  public int CourseID { get; set; }
  public string Title { get; set; }
  public int Credits { get; set; }
  public int DepartmentID { get; set; }
  public virtual Department Department { get; set; }
}

public class Department
{
   public Department()
   {
     this.Courses = new HashSet<Course>();
   }  
   public int DepartmentID { get; set; }
   public string Name { get; set; }
   public decimal Budget { get; set; }
   public DateTime StartDate { get; set; }
   public int? Administrator {get ; set; }
   public virtual ICollection<Course> Courses { get; set; }
}

Konfigurieren oder Zuordnen von Beziehungen

Auf der restlichen Seite wird erläutert, wie Sie mithilfe von Beziehungen auf Daten zugreifen und diese bearbeiten. Informationen zum Einrichten von Beziehungen in Ihrem Modell finden Sie auf den folgenden Seiten.

Erstellen und Ändern von Beziehungen

Wenn Sie die Beziehung ändern, ändert sich in einer Fremdschlüsselzuordnung der Status eines abhängigen Objekts mit einem EntityState.Unchanged Zustand in EntityState.Modified. In einer unabhängigen Beziehung aktualisiert das Ändern der Beziehung nicht den Status des abhängigen Objekts.

Die folgenden Beispiele zeigen, wie Sie die Fremdschlüsseleigenschaften und Navigationseigenschaften verwenden, um die zugehörigen Objekte zuzuordnen. Bei Fremdschlüsselzuordnungen können Sie entweder Methoden verwenden, um Beziehungen zu ändern, zu erstellen oder zu ändern. Bei unabhängigen Zuordnungen können Sie die Fremdschlüsseleigenschaft nicht verwenden.

  • Durch Zuweisen eines neuen Werts zu einer Fremdschlüsseleigenschaft wie im folgenden Beispiel.

    course.DepartmentID = newCourse.DepartmentID;
    
  • Der folgende Code entfernt eine Beziehung, indem der Fremdschlüssel auf NULL festgelegt wird. Beachten Sie, dass die Fremdschlüsseleigenschaft nullwertebar sein muss.

    course.DepartmentID = null;
    

    Hinweis

    Wenn sich der Verweis im hinzugefügten Zustand befindet (in diesem Beispiel das Kursobjekt), wird die Referenznavigationseigenschaft erst mit den Schlüsselwerten eines neuen Objekts synchronisiert, wenn SaveChanges aufgerufen wird. Die Synchronisierung erfolgt nicht, da der Objektkontext keine dauerhaften Schlüssel für hinzugefügte Objekte enthält, bis sie gespeichert werden. Wenn neue Objekte vollständig synchronisiert werden müssen, sobald Sie die Beziehung festgelegt haben, verwenden Sie eine der folgenden Methoden.*

  • Durch Zuweisen eines neuen Objekts zu einer Navigationseigenschaft. Der folgende Code erstellt eine Beziehung zwischen einem Kurs und einem department. Wenn die Objekte dem Kontext angefügt werden, wird die course ebenfalls zur department.Courses-Sammlung hinzugefügt, und die entsprechende Fremdschlüsseleigenschaft des course Objekts auf den Schlüsseleigenschaftswert der Abteilung festgelegt.

    course.Department = department;
    
  • Um die Beziehung zu löschen, legen Sie die Navigationseigenschaft auf null. Wenn Sie mit Entity Framework arbeiten, das auf .NET 4.0 basiert, muss das zugehörige Ende geladen werden, bevor Sie es auf NULL festlegen. Beispiel:

    context.Entry(course).Reference(c => c.Department).Load();
    course.Department = null;
    

    Ab Entity Framework 5.0, das auf .NET 4.5 basiert, können Sie die Beziehung auf NULL festlegen, ohne das zugehörige Ende zu laden. Sie können den aktuellen Wert auch mit der folgenden Methode auf NULL festlegen.

    context.Entry(course).Reference(c => c.Department).CurrentValue = null;
    
  • Durch Löschen oder Hinzufügen eines Objekts in einer Entitätssammlung. Beispielsweise können Sie der Course Auflistung ein Objekt vom Typ department.Courses hinzufügen. Dieser Vorgang erstellt eine Beziehung zwischen einem bestimmten Kurs und einem bestimmten department. Wenn die Objekte dem Kontext zugeordnet sind, wird die Abteilungsreferenz und die Fremdschlüsseleigenschaft des Kursobjekts auf die entsprechende departmentfestgelegt.

    department.Courses.Add(newCourse);
    
  • Mithilfe der ChangeRelationshipState Methode können Sie den Status der angegebenen Beziehung zwischen zwei Entitätsobjekten ändern. Diese Methode wird am häufigsten verwendet, wenn Sie mit N-Tier-Anwendungen und einer unabhängigen Zuordnung arbeiten (sie kann nicht mit einer Fremdschlüsselzuordnung verwendet werden). Um diese Methode zu verwenden, müssen Sie auch auf ObjectContext wechseln, wie im folgenden Beispiel gezeigt.
    Im folgenden Beispiel gibt es eine viele-zu-viele-Beziehung zwischen Kursleitern und Kursen. Durch das Aufrufen der ChangeRelationshipState Methode und das Übergeben des EntityState.Added Parameters wird dem SchoolContext signalisiert, dass eine Beziehung zwischen den beiden Objekten hinzugefügt wurde.

    
    ((IObjectContextAdapter)context).ObjectContext.
      ObjectStateManager.
      ChangeRelationshipState(course, instructor, c => c.Instructor, EntityState.Added);
    

    Wenn Sie eine Beziehung aktualisieren (nicht nur hinzufügen), müssen Sie die alte Beziehung löschen, nachdem Sie die neue hinzugefügt haben:

    ((IObjectContextAdapter)context).ObjectContext.
      ObjectStateManager.
      ChangeRelationshipState(course, oldInstructor, c => c.Instructor, EntityState.Deleted);
    

Synchronisieren der Änderungen zwischen den Fremdschlüsseln und Navigationsattributen

Wenn Sie die Beziehung der dem Kontext angefügten Objekte mithilfe einer der oben beschriebenen Methoden ändern, muss Entity Framework Fremdschlüssel, Verweise und Auflistungen synchron halten. Entity Framework verwaltet diese Synchronisierung automatisch (auch als Beziehungskorrektur bezeichnet) für die POCO-Entitäten mit Proxys. Weitere Informationen finden Sie unter Arbeiten mit Proxys.

Wenn Sie POCO-Entitäten ohne Proxys verwenden, müssen Sie sicherstellen, dass die DetectChanges-Methode aufgerufen wird, um die zugehörigen Objekte im Kontext zu synchronisieren. Beachten Sie, dass die folgenden APIs automatisch einen DetectChanges-Aufruf auslösen.

  • DbSet.Add
  • DbSet.AddRange
  • DbSet.Remove
  • DbSet.RemoveRange
  • DbSet.Find
  • DbSet.Local
  • DbContext.SaveChanges
  • DbSet.Attach
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries
  • Ausführen einer LINQ-Abfrage für eine DbSet

In Entity Framework verwenden Sie häufig Navigationseigenschaften, um Entitäten zu laden, die mit der zurückgegebenen Entität durch die definierte Zuordnung verknüpft sind. Weitere Informationen finden Sie unter Laden verwandter Objekte.

Hinweis

Wenn Sie ein Ende der Beziehung eines abhängigen Objekts in einer Fremdschlüsselbeziehung laden, wird das zugehörige Objekt basierend auf dem Fremdschlüsselwert des abhängigen Objekts geladen, das sich derzeit im Arbeitsspeicher befindet.

    // Get the course where currently DepartmentID = 2.
    Course course = context.Courses.First(c => c.DepartmentID == 2);

    // Use DepartmentID foreign key property
    // to change the association.
    course.DepartmentID = 3;

    // Load the related Department where DepartmentID = 3
    context.Entry(course).Reference(c => c.Department).Load();

In einer unabhängigen Zuordnung wird das zugehörige Ende eines abhängigen Objekts basierend auf dem Fremdschlüsselwert abgefragt, der sich derzeit in der Datenbank befindet. Wenn die Beziehung geändert wurde und die Referenzeigenschaft für das abhängige Objekt auf ein anderes Prinzipalobjekt verweist, das im Objektkontext geladen wird, versucht Entity Framework jedoch, eine Beziehung zu erstellen, wie sie auf dem Client definiert ist.

Verwalten der Parallelität

In Fremdschlüsseln und unabhängigen Zuordnungen basieren Parallelitätsprüfungen auf den Entitätsschlüsseln und anderen Entitätseigenschaften, die im Modell definiert sind. Wenn Sie den EF Designer zum Erstellen eines Modells verwenden, legen Sie das ConcurrencyMode Attribut auf fixed fest, um anzugeben, dass die Eigenschaft auf Parallelität überprüft werden soll. Wenn Sie Code First zum Definieren eines Modells verwenden, verwenden Sie die ConcurrencyCheck Anmerkung für Eigenschaften, die auf Parallelität überprüft werden sollen. Beim Arbeiten mit Code First können Sie auch die TimeStamp Anmerkung verwenden, um anzugeben, dass die Eigenschaft auf Parallelität überprüft werden soll. Nur eine einzige Zeitstempeleigenschaft ist in einer bestimmten Klasse zulässig. Code First ordnet diese Eigenschaft einem nicht nullfähigen Feld in der Datenbank zu.

Es wird empfohlen, immer die Fremdschlüsselzuordnung zu verwenden, wenn Sie mit Entitäten arbeiten, die an der Parallelitätsprüfung und -auflösung teilnehmen.

Weitere Informationen finden Sie unter Behandeln von Parallelitätskonflikten.

Arbeiten mit überlappenden Tasten

Überlappende Schlüssel sind zusammengesetzte Schlüssel, bei denen einige Eigenschaften im Schlüssel ebenfalls Teil eines anderen Schlüssels in der Entität sind. Sie können keinen überlappenden Schlüssel in einer unabhängigen Zuordnung haben. Um eine Fremdschlüsselzuordnung zu ändern, die überlappende Schlüssel enthält, empfiehlt es sich, die Fremdschlüsselwerte zu ändern, anstatt die Objektverweise zu verwenden.