Datenbindung (LINQ to SQL)

Aktualisiert: November 2007

LINQ to SQL unterstützt das Binden an allgemeine Steuerelemente, z. B. an Rastersteuerelemente. LINQ to SQL definiert vor allem das Grundmuster für die Bindung an ein Datenraster und für den Umgang mit der Master-Detail-Bindung im Hinblick auf Anzeige und Aktualisierung.

Zugrunde liegendes Prinzip

LINQ to SQL übersetzt LINQ-Abfragen zur Ausführung in einer Datenbank in SQL. Die Ergebnisse sind IEnumerable mit strikter Typbindung. Da es sich hierbei um gewöhnliche Common Language Runtime (CLR)-Objekte handelt, lassen sich die Ergebnisse mithilfe von gewöhnlicher Objektdatenbindung darstellen. Andererseits erfordern Änderungsoperationen (Einfügungen, Aktualisieren, Löschen) zusätzliche Schritte.

Operation

Die implizite Bindung an Windows Forms-Steuerelemente erfolgt durch Implementierung von IListSource. Generische Datenquellen für Table<TEntity> (Table<T> in C# oder Table(Of T) in Visual Basic) und generische DataQuery wurden aktualisiert, um IListSource zu implementieren. Datenbindungsmodule der Benutzeroberfläche (UI) (Windows Forms und Windows Presentation Foundation) prüfen, ob ihre Datenquelle IListSource implementiert. Aus diesem Grund wird beim Schreiben des direkten Einflusses einer Abfrage auf eine Datenquelle eines Steuerelements implizit die Erzeugung der LINQ to SQL-Auflistung aufgerufen. Siehe hierzu das folgende Beispiel:

Dim dataGrid1 As New DataGrid()
Dim dataGrid2 As New DataGrid()
Dim dataGrid3 As New DataGrid()

Dim custQuery = _
    From cust In db.Customers _
    Select cust

dataGrid1.DataSource = custQuery
dataGrid2.DataSource = custQuery
dataGrid2.DataMember = "Orders"

Dim bs = _
    New BindingSource()
bs.DataSource = custQuery
dataGrid3.DataSource = bs
DataGrid dataGrid1 = new DataGrid();
DataGrid dataGrid2 = new DataGrid();
DataGrid dataGrid3 = new DataGrid();

var custQuery =
    from cust in db.Customers
    select cust;
dataGrid1.DataSource = custQuery;
dataGrid2.DataSource = custQuery;
dataGrid2.DataMember = "Orders";

BindingSource bs = new BindingSource();
bs.DataSource = custQuery;
dataGrid3.DataSource = bs;

Das Gleiche geschieht bei Windows Presentation Foundation:

Dim listView1 As New ListView()
Dim custQuery2 = _
From cust In db.Customers _
Select cust

Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2
ListView listView1 = new ListView();
var custQuery2 =
    from cust in db.Customers
    select cust;

ListViewItem ItemsSource = new ListViewItem();
ItemsSource = (ListViewItem)custQuery2;

Auflistungsgenerierungen werden von generischem Table<TEntity> und generischem DataQuery in GetList implementiert.

IListSource-Implementierung

LINQ to SQL implementiert IListSource an zwei Stellen:

  • Die Datenquelle ist eine Table<TEntity>: LINQ to SQL durchsucht die Tabelle, um eine DataBindingList-Auflistung zu füllen, die einen Verweis auf die Tabelle beibehält.

  • Die Datenquelle ist eine IQueryable<T>. Es existieren zwei Szenarien:

    • Findet LINQ to SQL die zugrunde liegende Table<TEntity> in der IQueryable<T>, ermöglicht die Quelle das Bearbeiten, und die Situation entspricht jener im ersten Listenpunkt.

    • Kann LINQ to SQL die zugrunde liegende Table<TEntity> nicht finden, ermöglicht die Quelle keine Bearbeitung (z. B. groupby). LINQ to SQL durchsucht die Abfrage, um eine generische SortableBindingList zu füllen, die eine einfache BindingList<T> ist und die Sortierfunktion für T-Entitäten einer gegebenen Eigenschaft implementiert.

Spezialisierte Auflistungen

Bei vielen zuvor in diesem Dokument beschriebenen Features wurde BindingList<T> auf abweichende Klassen spezialisiert. Diese Klassen sind generische SortableBindingList und generische DataBindingList. Beide werden als intern deklariert.

Generische SortableBindingList

Diese Klasse erbt von BindingList<T> und ist eine durchsuchbare Version von BindingList<T>. Die Sortierung ist eine Lösung im Arbeitsspeicher, die niemals einen Kontakt zur Datenbank herstellt. BindingList<T> implementiert IBindingList, unterstützt jedoch standardmäßig keine Sortierung. BindingList<T> implementiert jedoch IBindingList mit virtuellen Kernmethoden. Sie können diese Methoden leicht überschreiben. Die generische SortableBindingList überschreibt SupportsSortingCore, SortPropertyCore, SortDirectionCore und ApplySortCore.ApplySortCore wird von ApplySort aufgerufen und sortiert die Liste der T-Elemente einer gegebenen Eigenschaft.

Wenn die Eigenschaft nicht zu T gehört, wird eine Ausnahme ausgelöst.

Zur Sortierung erstellt LINQ to SQL eine generische SortableBindingList.PropertyComparer-Klasse, die von einem generischen IComparer.Compare erbt, und implementiert einen Standardvergleich für einen gegebenen Typ T, einen PropertyDescriptor und eine Richtung. Diese Klasse erstellt dynamisch einen Comparer von T, bei dem T der PropertyType des PropertyDescriptor ist. Dann wird der Standardvergleich vom statischen generischen Comparer abgerufen. Eine Standardinstanz wird durch Reflektion erzeugt.

Eine generische SortableBindingList ist auch die Basisklasse für DataBindingList. Eine generische SortableBindingList bietet zwei virtuelle Methoden zum Unterbrechen oder Fortsetzen der Verfolgung des Hinzufügens/Entfernens von Elementen. Diese beiden Methoden lassen sich für Basisfeatures wie Sortierung verwenden, werden jedoch tatsächlich von höheren Klassen wie der generischen DataBindingList implementiert.

Generische DataBindingList

Diese Klasse erbt von der generischen SortableBindingLIst. Die generische DataBindingList behält einen Verweis auf die zugrunde liegende generische Table der generischen IQueryable bei, die für das erste Füllen der Auflistung verwendet wurde. Die generische DatabindingList fügt die Verfolgung für das Hinzufügen/Entfernen von Elementen hinzu, indem Sie InsertItem() und RemoveItem() überschreiben. Außerdem wird das abstrakte Feature zur Unterbrechung/Wiederaufnahme der Verfolgung implementiert, um eine bedingte Verfolgung zu ermöglichen. Mit diesem Feature nutzt die generische DataBindingList die Vorteile der polymorphen Verwendung der Verfolgungsfunktion für übergeordnete Klassen.

Binden an EntitySets

Eine Bindung an EntitySet ist ein Sonderfall, da EntitySet bereits eine Auflistung ist, die IBindingList implementiert. LINQ to SQL fügt die Unterstützung für Sortierung und das Abbrechen (ICancelAddNew) hinzu. Eine EntitySet-Klasse verwendet eine interne Liste, um Entitäten zu speichern. Diese Liste ist eine Auflistung auf niedriger Ebene, die auf einem generischen Array, der generischen ItemList-Klasse, basiert.

Hinzufügen eines Sortierungsfeatures

Arrays bieten eine Sortiermethode (Array.Sort()), die Sie zusammen mit einem Comparer von T verwenden können. LINQ to SQL verwendet die weiter oben in diesem Thema beschriebene generische SortableBindingList.PropertyComparer-Klasse, um diesen Comparer für die Eigenschaft und die Sortierrichtung zu erhalten. Eine ApplySort-Methode wird der generischen ItemList hinzugefügt, um dieses Feature aufzurufen.

Auf der EntitySet-Seite müssen Sie jetzt die Sortierungsunterstützung deklarieren:

  • SupportsSorting gibt true zurück.

  • ApplySort ruft entities.ApplySort() und dann OnListChanged() auf.

  • Die SortDirection-Eigenschaft und die SortProperty-Eigenschaft zeigen die aktuelle Sortierungsdefinition, die in lokalen Membern gespeichert wird.

Zwischenspeichern

LINQ to SQL-Abfragen implementieren GetList. Trifft die Windows Forms-BindingSource-Klasse auf diese Schnittstelle, wird GetList() für eine Verbindung dreimal aufgerufen. Um diese Situation zu umgehen, implementiert LINQ to SQL einen Cache je Instanz, um stets die gleiche erzeugte Auflistung zu speichern und zurückzugeben.

Abbruch

IBindingList definiert eine AddNew-Methode, die von Steuerelementen genutzt wird, um ein neues Element aus einer Bindungsauflistung zu erstellen. Das DataGridView-Steuerelement zeigt diese Funktion sehr gut, wenn die letzte sichtbare Zeile ein Sternchen in der Überschrift enthält. Das Sternchen zeigt an, dass Sie ein neues Element hinzufügen können.

Zusätzlich zu diesem Feature kann eine Auflistung auch ICancelAddNew implementieren. Mit diesem Feature können Steuerelemente den Vorgang abbrechen oder validieren, ob das neu bearbeitete Element validiert wurde oder nicht.

ICancelAddNew wird in allen LINQ to SQL-Auflistungen mit Datenbindung implementiert (generische SortableBindingList und generischer EntitySet). In beiden Implementierungen verhält sich der Code wie folgt:

  • Lässt das Einfügen und Entfernen von Elementen in die bzw. aus der Auflistung zu.

  • Verfolgt keine Änderungen, solange die Benutzeroberfläche keinen Commit für die Bearbeitung ausführt.

  • Verfolgt keine Änderungen, so lange die Bearbeitung abgebrochen wird (CancelNew).

  • Ermöglicht die Verfolgung, wenn die Bearbeitung aktiviert wurde (EndNew).

  • Sorgt für das normale Verhalten der Auflistung, wenn das neue Element nicht aus AddNew stammt.

Problembehandlung

Dieser Abschnitt erläutert verschiedene Elemente, die Sie bei der Fehlerbehebung von LINQ to SQL-Datenbindungsanwendungen unterstützen können.

  • Sie müssen Eigenschaften verwenden. Die ausschließliche Verwendung von Feldern genügt nicht. Windows Forms erfordert diese Verwendung.

  • Standardmäßig werden die Datenbanktypen image, varbinary und timestamp dem Bytearray zugeordnet. Da ToString() in diesem Szenario nicht unterstützt wird, können diese Objekte nicht angezeigt werden.

  • Ein Klassenmember, der einem Primärschlüssel zugeordnet wurde, verfügt über einen Setter. LINQ to SQL unterstützt jedoch keine Änderungen der Objektidentität. Deshalb kann der primäre/eindeutige Schlüssel, der in der Zuordnung verwendet wird, nicht in der Datenbank aktualisiert werden. Eine Änderung im Raster verursacht beim Aufrufen von SubmitChanges eine Ausnahme.

  • Wird eine Entität an zwei separate Raster gebunden (z. B. für Master und Details), wird Delete im Master-Raster nicht an das Detail-Raster weitergeleitet>.

Siehe auch

Weitere Ressourcen

Hintergrundinformationen (LINQ to SQL)