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 generischeSortableBindingList
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 dannOnListChanged()
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
undtimestamp
dem Bytearray zugeordnet. DaToString()
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>.