Freigeben über


Datenbindung

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 für die 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.

Vorgang

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. Datenbindungs-Engines 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-Sammlung aufgerufen. Siehe hierzu das folgende Beispiel:

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

Das Gleiche geschieht bei Windows Presentation Foundation:

ListView listView1 = new ListView();
var custQuery2 =
    from cust in db.Customers
    select cust;

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

Dim ItemsSource As New ListViewItem
ItemsSource = custQuery2

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

IListSource-Implementierung

LINQ to SQL implementiert IListSource an zwei Speicherorten:

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

  • Die Datenquelle ist eine IQueryable<T>. Es gibt 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.

    • Wenn LINQ to SQL die zugrunde liegende Table<TEntity> nicht finden kann, lässt die Quelle keine Edition zu (z. B groupby). LINQ to SQL browst die Abfrage, um eine generische SortableBindingList zu füllen, die eine einfache BindingList<T> ist, und das Sortierfeature für T-Entitäten einer gegebenen Eigenschaft implementiert.

Spezialisierte Auflistungen

Bei vielen zuvor in diesem Dokument beschriebenen Funktionen 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 dem virtuellen core-Methoden. 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 Basisfunktionen 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 die abstrakte Funktion zur Unterbrechung/Wiederaufnahme der Verfolgung implementiert, um eine bedingte Verfolgung zu ermöglichen. Mit dieser Funktion 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 Sortier- und Abbruchunterstützung (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 einer Sortierungsfunktion

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 Artikel 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 diese Funktion aufzurufen.

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

  • true gibt SupportsSorting 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.

Wenn Sie eine „System.Windows.Forms.BindingSource“ verwenden und eine „EntitySet<TEntity>“ an die „System.Windows.Forms.BindingSource.DataSource“ binden, müssen Sie „EntitySet<TEntity>.GetNewBindingList“ aufrufen, um „BindingSource.List“ zu aktualisieren.

Wenn Sie eine „System.Windows.Forms.BindingSource“ verwenden, die „BindingSource.DataMember“-Eigenschaft festgelegt haben und für die „BindingSource.DataSource“ eine Klasse mit einer Eigenschaft festgelegt haben, die im „BindingSource.DataMember“ angegeben ist, der die „EntitySet<TEntity>“ verfügbar macht, müssen Sie „EntitySet<TEntity>.GetNewBindingList“ nicht aufrufen, um die „BindingSource.List“ zu aktualisieren. Dabei geht jedoch die Sortierfunktion verloren.

Caching

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 Sammlung 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 dieser Funktion kann eine Auflistung auch ICancelAddNew implementieren. Mit dieser Funktion können Steuerelemente den Vorgang abbrechen oder validieren, ob das neu bearbeitete Element validiert wurde oder nicht.

ICancelAddNew wird in allen LINQ to SQL-Sammlung 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