Freigeben über


Datenbindung

LINQ to SQL unterstützt die Bindung an allgemeine Steuerelemente, z. B. Rastersteuerelemente. Insbesondere definiert LINQ to SQL die grundlegenden Muster für die Bindung an ein Datenraster und die Verarbeitung von Master-Detail-Bindung sowohl im Hinblick auf die Anzeige als auch die 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 bei diesen Objekten um gewöhnliche CLR-Objekte (Common Language Runtime) handelt, können gewöhnliche Objektdatenbindungen verwendet werden, um die Ergebnisse anzuzeigen. Andererseits erfordern Änderungsvorgänge (Einfügungen, Aktualisierungen und Löschvorgänge) zusätzliche Schritte.

Vorgang

Die implizite Bindung an Windows Forms-Steuerelemente erfolgt durch das Implementieren IListSource. Generische Datenquellen Table<TEntity> (Table<T> in C# oder Table(Of T) in Visual Basic) und generische DataQuery wurden aktualisiert, um IListSource zu implementieren. Benutzeroberflächen-Datenbindungsmodule (Windows Forms und Windows Presentation Foundation) testen jeweils, ob ihre Datenquelle IListSource implementiert. Daher ruft das direkte Zuweisen einer Abfrage an eine Datenquelle eines Steuerelements implizit eine LINQ-to-SQL-Auflistungserstellung auf, wie im folgenden Beispiel gezeigt:

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

Dasselbe geschieht mit 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 Stellen:

  • Die Datenquelle ist eine Table<TEntity>: LINQ to SQL durchsucht die Tabelle, um eine DataBindingList Auflistung auszufüllen, die einen Verweis auf die Tabelle behä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 den zugrunde liegenden Table<TEntity> nicht finden kann, lässt die Quelle keine Bearbeitung zu (z. B. groupby). LINQ to SQL durchsucht die Abfrage, um ein generisches SortableBindingList auszufüllen, das ein einfaches BindingList<T> ist und das Sortierfeature für T-Entitäten in Bezug auf eine bestimmte Eigenschaft implementiert.

Spezialisierte Sammlungen

Für viele Features, die weiter oben in diesem Dokument beschrieben wurden, wurde BindingList<T> auf einige verschiedene Klassen spezialisiert. Diese Klassen sind generisch SortableBindingList und generisch DataBindingList. Beide werden als intern deklariert.

Generische SortableBindingList

Diese Klasse erbt von BindingList<T>, und ist eine sortierbare Version von BindingList<T>. Beim Sortieren handelt es sich um eine Speicherlösung, die niemals die Datenbank selbst kontaktiert. BindingList<T> implementiert IBindingList , unterstützt jedoch die Sortierung nicht standardmäßig. BindingList<T> Implementiert IBindingList jedoch mit virtuellen Kernmethoden. Sie können diese Methoden leicht überschreiben. Die generische SortableBindingList überschreibt SupportsSortingCore, SortPropertyCore, SortDirectionCore und ApplySortCore. ApplySortCore wird aufgerufen und ApplySort sortiert die Liste der T-Elemente für eine bestimmte Eigenschaft.

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

Um die Sortierung zu erreichen, erstellt LINQ to SQL eine generische SortableBindingList.PropertyComparer Klasse, die von generic IComparer.Compare erbt und einen Standardvergleich für einen bestimmten Typ T, a PropertyDescriptorund eine Richtung implementiert. Diese Klasse erstellt dynamisch einen Comparer von T, bei dem T der PropertyType des PropertyDescriptor ist. Anschließend wird der Standard-Comparer aus der statischen generischen Generika Comparerabgerufen. Eine Standardinstanz wird durch Reflektion erzeugt.

Generic 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 können für Basisfeatures wie das Sortieren verwendet werden, werden aber tatsächlich von Oberklassen wie generischen DataBindingListimplementiert.

Generische DataBindingList

Diese Klasse erbt von dem 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

Die Bindung an EntitySet ist ein Sonderfall, da EntitySet bereits eine Sammlung ist, die IBindingList implementiert. LINQ to SQL fügt Sortier- und Abbruchunterstützung hinzuICancelAddNew. Eine EntitySet Klasse verwendet eine interne Liste zum Speichern von Entitäten. Diese Liste ist eine Auflistung auf niedriger Ebene basierend auf einem generischen Array, der generischen ItemList Klasse.

Hinzufügen eines Sortierfeatures

Arrays bieten eine Sortiermethode (Array.Sort()), die Sie mit einer Comparer von T verwenden können. LINQ to SQL verwendet die weiter oben in diesem Thema beschriebene generische SortableBindingList.PropertyComparer Klasse, um dies Comparer für die Eigenschaft und die Richtung abzurufen, nach der sortiert werden soll. Eine ApplySort-Methode wird der generischen ItemList hinzugefügt, um diese Funktion aufzurufen.

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

Wenn Sie eine System.Windows.Forms.BindingSource verwenden und ein EntitySet<TEntity> an 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.

Zwischenspeicherung

LINQ to SQL-Abfragen implementieren GetList. Wenn die Windows Forms BindingSource-Klasse diese Schnittstelle erfüllt, ruft sie GetList() dreimal für eine einzelne Verbindung auf. Um diese Situation zu umgehen, implementiert LINQ to SQL einen Cache pro Instanz, um sie zu speichern und immer dieselbe generierte Auflistung zurückzugeben.

Abbruch

IBindingList definiert eine AddNew Methode, die von Steuerelementen zum Erstellen eines neuen Elements aus einer gebundenen Auflistung verwendet wird. Das DataGridView Steuerelement zeigt dieses Feature sehr gut an, wenn die letzte sichtbare Zeile einen Stern in der Kopfzeile enthält. Der Stern zeigt Ihnen, dass Sie ein neues Element hinzufügen können.

Zusätzlich zu dieser Funktion kann eine Sammlung auch ICancelAddNew implementieren. Dieses Feature ermöglicht es den Steuerelementen, abzubrechen oder zu überprüfen, ob das neue bearbeitete Element überprüft wurde oder nicht.

ICancelAddNew wird in allen LINQ to SQL-datengebundenen Sammlungen (generic SortableBindingList und generic EntitySet) implementiert. In beiden Implementierungen funktioniert der Code wie folgt:

  • Ermöglicht das Einfügen und Entfernen von Elementen aus der Auflistung.

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

  • Änderungen werden nicht nachverfolgt, solange die Edition 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

In diesem Abschnitt werden mehrere Elemente aufgerufen, die ihnen bei der Problembehandlung bei LINQ to SQL-Datenbindungsanwendungen helfen können.

  • Sie müssen Eigenschaften verwenden; Die Verwendung von Feldern reicht nicht aus. Windows Forms erfordert diese Verwendung.

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

  • Ein einem Primärschlüssel zugeordnetes Klassenmitglied hat einen Setter, aber LINQ to SQL unterstützt keine Objektidentitätsänderung. Daher kann der primär/eindeutige Schlüssel, der in der Zuordnung verwendet wird, nicht in der Datenbank aktualisiert werden. Eine Änderung im Raster verursacht eine Ausnahme beim Aufrufen von SubmitChanges.

  • Wenn eine Entität in zwei separaten Rastern gebunden ist (z. B. ein Master-Raster und ein weiteres Detailraster), wird ein Delete im Masterraster nicht an das Detailraster weitergegeben.

Siehe auch