Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 5. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Weitere .NET-Datentypen
7 Weitere Möglichkeiten von C#
8 Auflistungsklassen (Collections)
9 Fehlerbehandlung und Debugging
10 LINQ to Objects
11 Multithreading und die Task Parallel Library (TPL)
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 Einige wichtige .NET-Klassen
15 Projektmanagement und Visual Studio 2010
16 XML
17 WPF – Die Grundlagen
18 WPF-Containerelemente
19 WPF-Steuerelemente
20 Konzepte der WPF
21 Datenbindung
22 2D-Grafik
23 ADO.NET – verbindungsorientierte Objekte
24 ADO.NET – Das Command-Objekt
25 ADO.NET – Der SqlDataAdapter
26 ADO.NET – Daten im lokalen Speicher
27 ADO.NET – Aktualisieren der Datenbank
28 Stark typisierte DataSets
29 LINQ to SQL
30 Weitergabe von Anwendungen
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual C# 2010 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2010

Visual C# 2010
geb., mit DVD
1295 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1552-7
Pfeil 29 LINQ to SQL
Pfeil 29.1 Allgemeine Grundlagen
Pfeil 29.2 Objektzuordnung mit Entitätsklassen
Pfeil 29.3 Mapping von Objekten
Pfeil 29.3.1 Das »Table«-Attribut
Pfeil 29.3.2 Das »Column«-Attribut
Pfeil 29.4 Verknüpfungen zwischen Entitäten
Pfeil 29.4.1 Der Typ »EntityRef<T>«
Pfeil 29.4.2 Verzögertes Laden
Pfeil 29.4.3 Der Typ »EntitySet<T>«
Pfeil 29.4.4 Ein weiteres Beispiel
Pfeil 29.4.5 Sofortiges Laden der Daten
Pfeil 29.5 Tools zur Erzeugung von Entitätsklassen
Pfeil 29.6 Die Klasse »DataContext«
Pfeil 29.6.1 Verbindungsaufbau
Pfeil 29.6.2 Daten abfragen
Pfeil 29.6.3 Von einer LINQ-Abfrage erzeugtes SQL-Statement ausgeben
Pfeil 29.6.4 Aktualisieren der Daten
Pfeil 29.6.5 Konflikte behandeln
Pfeil 29.7 Der LINQ to SQL-Designer (O/R-Designer)
Pfeil 29.7.1 Handhabung des O/R-Designers
Pfeil 29.7.2 Die abgeleitete »DataContext«-Klasse
Pfeil 29.7.3 Entitätsklassen


Galileo Computing - Zum Seitenanfang

29.7 Der LINQ to SQL-Designer (O/R-Designer) Zur nächsten ÜberschriftZur vorigen Überschrift


Galileo Computing - Zum Seitenanfang

29.7.1 Handhabung des O/R-Designers Zur nächsten ÜberschriftZur vorigen Überschrift

Wenn Sie die Kapitel 23 bis 28 zu ADO.NET aufmerksam gelesen haben und jetzt an dieser Stelle einen Vergleich zwischen ADO.NET und LINQ to SQL anstellen, werden Sie vermutlich zu dem Schluss kommen, dass der technologische Hintergrund von LINQ to SQL auf ADO.NET basiert. Beide Bibliotheken ähneln sich in vielfacher Hinsicht, aber die Codeimplementierung ist mit LINQ to SQL einfacher und überschaubarer geworden, während sich gleichzeitig die Anzahl der eingesetzten Klassen deutlich reduziert hat. Im Grunde genommen rankt sich alles nur noch um das DataContext-Objekt.

Abbildung 29.2 Das Element »LINQ to SQL-Klassen« hinzufügen

Allerdings gibt es momentan auch einen Wermutstropfen: Die Definition der Entitätsklassen ist sehr aufwendig und scheint die programmiertechnischen Vorteile zunichte zu machen. Aber diese scheinbare Problematik wird von Visual Studio selbst gelöst, denn es stellt einen integrierten Designer zur Verfügung, der es ermöglicht, mittels Drag & Drop die notwendigen Klassen zu erzeugen.

Wir wollen uns das Arbeiten mit dem Designer sofort an einem konkreten Beispiel ansehen und dazu die Tabelle Products der Northwind-Datenbank benutzen. Deshalb starten wir ein Windows Forms-Projekt. Nach dem Anlegen des Projekts markieren Sie im Projektmappen-Explorer das Projekt und öffnen dessen Kontextmenü. Über Hinzufügen Neues Element… gelangen Sie zu dem in Abbildung 29.2 gezeigten Auswahldialog, in dem Sie LINQ to SQL-Klassen auswählen. Da wir anschließend auf eine Tabelle der Northwind-Datenbank zugreifen wollen, bietet es sich an, abweichend von der Vorgabe die erzeugte Datei Northwind.dbml zu nennen.

Nach der Bestätigung im Dialogfenster wird in Visual Studio der O/R-Designer geöffnet (siehe Abbildung 29.3), in dem später die Entitätsklassen und gegebenenfalls auch deren Beziehung grafisch dargestellt werden.

Abbildung 29.3 Der O/R-Designer

Als Nächstes müssen wir die Datenbankverbindung definieren und anschließend die Tabelle Products angeben. Dazu dient das Tool Server-Explorer, das über das Menü Ansicht von Visual Studio geöffnet werden kann. Im Server-Explorer werden über den Knoten Datenverbindungen die Verbindungen angezeigt, die Sie in Visual Studio angelegt haben. Wird Ihnen hier bereits die Northwind-Datenbank angeboten, können Sie diese benutzen. Ansonsten legen Sie eine neue Datenverbindung über das Kontextmenü Datenverbindungen an.

Sobald im Server-Explorer die Verbindung zur Northwind-Datenbank erstellt ist, markieren Sie im untergeordneten Knoten Tabellen die Tabelle Products und ziehen diese in den linken Fensterbereich des O/R-Designers. Danach wird die Tabelle im Designer mit allen ihren Feldern visualisiert dargestellt (siehe Abbildung 29.4). Möchten Sie mit gespeicherten Prozeduren oder Funktionen arbeiten, müssen Sie diese aus dem Server-Explorer in den rechten Fensterbereich des Designers ziehen.

Abbildung 29.4 Die Entity-Klasse der Tabelle »Products« im O/R-Designer

Bis jetzt wurden mehrere Dateien dem aktuellen Projekt hinzugefügt:

  • eine DBML-Datei (hier: Northwind.dbml), hinter der sich die Definition der Metadaten der Entitätsklasse im XML-Format verbirgt. In Abbildung 29.5 sehen Sie den Inhalt der generierten DBML-Datei.
  • die Datei Northwind.dbml.layout, die Informationen für das Layout im Designer enthält
  • die Datei Northwind.designer.cs, die die generierten Klassen enthält

Darüber hinaus wird dem Projekt auch die Anwendungskonfigurationsdatei app.config hinzugefügt, in der die Verbindungsinformationen zu der ausgewählten Datenbank eingetragen sind. Sie können also zu einem späteren Zeitpunkt die Verbindungsdaten jederzeit an die der Produktivumgebung anpassen.

Abbildung 29.5 Inhalt der ».dbml«-Datei

Die Datei Northwind.designer.cs beschreibt in unserem Beispiel zwei Klassendefinitionen: Es handelt sich einerseits um die Klasse NorthwindDataContext, die von der Klasse DataContext abgeleitet ist und unter anderem für den Verbindungsaufbau zum SQL Server zuständig ist. Die zweite Klasse ist die Entitätsklasse Products. Diese Klasse beschreibt alle Spalten der Originaltabelle, die aber bei Bedarf auch auf die benötigten Spalten reduziert werden können. Bedenken Sie aber, dass später nur die Daten der Spalten abgefragt werden, die tatsächlich benötigt werden. Sprechen nicht schwerwiegende Gründe gegen die Aufnahme aller Spalten in der Entitätsklasse (z. B. Sicherheitsaspekte), sollten Sie keine Reduzierung vornehmen.

Sowohl die Definition der DataContext-Klasse als auch die Definition der Entitätsklasse sollten wir uns etwas genauer ansehen. Beide beherbergen Klassenmitglieder, die über das hinausgehen, was in Abschnitt 29.6, »Die Klasse ›DataContext‹«, erörtert worden ist.


Galileo Computing - Zum Seitenanfang

29.7.2 Die abgeleitete »DataContext«-Klasse Zur nächsten ÜberschriftZur vorigen Überschrift

Die Klasse NorthwindDataContext ist von der Klasse DataContext abgeleitet. Im Wesentlichen bietet sie uns für jede verwaltete Entitätsklasse einen vereinfachten Zugriff über eine Eigenschaft, die so heißt wie die Entitätsklasse selbst. Haben wir im O/R-Designer die Tabelle Products hinzugefügt (und den Klassenbezeichner in Product geändert), sieht der automatisch generierte Code wie folgt aus:


public System.Data.Linq.Table<Product> Product {
  get {
    return this.GetTable<Product>();
  }
}

Damit ist es möglich, mit


NorthwindDataContext context = new NorthwindDataContext();
Table<Product> products = context.Product;

direkt eine Liste der Product-Entitäten zu erstellen. Ein wenig erinnert uns das an typisierte DataSets.

Neben mehreren Konstruktoren, deren Parameterlisten sich nicht von denen der Basisklasse unterscheiden, weist die abgeleitete DataContext-Klasse eine Reihe partieller Methoden auf. Partielle Methoden sind mit C# 3.0 eingeführt worden. Sie sind eine logische Fortsetzung der Idee partieller Klassen. Sind in einer Klasse partielle Methoden definiert, können diese in einer Erweiterung der partiellen Klasse definiert werden. Betrachten wir dazu ein einfaches Beispiel:


partial class DataObject {
  partial void OnCreated();
  public DataObject() {
    OnCreated();
  }
}

In der Klasse DataObject ist die partielle Methode OnCreated definiert. Grundsätzlich dürfen partielle Methoden nur void sein. Ein Zugriffsmodifizierer ist unzulässig, partielle Methoden sind daher immer private. Wird ein Objekt der Klasse DataObject erzeugt, passiert noch nichts, denn der Compiler ignoriert die partielle Methode, da sie keinen Code enthält.

Eine partielle Methode müssen Sie als ein Angebot ansehen, das Sie annehmen können oder nicht – vergleichbar mit dem Angebot, auf ein Ereignis zu reagieren oder nicht. Deshalb finden Sie sehr häufig Hinweise auf die nahe Verwandtschaft von Ereignissen und partiellen Methoden.

Erweitern Sie die Klasse DataObject, können Sie die partielle Methode implementieren.


partial class DataObject {
  partial void OnCreated() {
    Console.WriteLine("In der partiellen Methode");
  }
} 

Beim Kompilieren wird aus den beiden separaten Klassendefinitionen eine Klasse erzeugt, wobei nun auch die partielle Methode berücksichtigt wird. Wird beim Instanziieren der Klasse DataObject der Konstruktor aufgerufen, wird auch die partielle Methode ausgeführt.

Nach dieser Erläuterung kehren wir zu der DataContext-Klasse zurück, die in unserem Beispiel vier partielle Methoden anbietet:


partial void OnCreated();
partial void InsertProduct(Product instance);
partial void UpdateProduct(Product instance);
partial void DeleteProduct(Product instance);

OnCreated wird in jedem Konstruktor aufgerufen. Möchten Sie bei der Instanziierung noch weitere Operationen begleitend ausführen lassen, fügen Sie dem Projekt eine neue Klassendefinition hinzu und implementieren die Methode OnCreated, wie im folgenden Codefragment zu sehen ist:


partial class NorthwindDataContext {
  partial void OnCreated() {
    // Anweisungen
  }
}

Kommen wir nun zu den anderen drei partiellen Methoden InsertXxx, UpdateXxx und DeleteXxx. Diesen drei Methoden ist als Suffix der Bezeichner der Entitätsklasse angehängt. Wie Sie wissen, wird die Datenbank durch den Aufruf der Methode SubmitChanges aktualisiert. Die erforderlichen SQL-Statements werden dabei automatisch erzeugt und können durch das Attribut UpdateCheck beeinflusst werden. In den meisten Fällen ist das vollkommen ausreichend, um Einfluss auf die Aktualisierung auszuüben.

Ist eine Aktualisierungsoperation gefordert, die über die vorgegebenen Möglichkeiten hinausgeht, können Sie durch Implementierung der drei Methoden die Vorgabe überschreiben. Wenn wir beispielsweise annehmen, Sie möchten die Preise aller Artikel der Products-Tabelle verdoppeln, dann könnten Sie mit


partial class NorthwindDataContext {
  partial void UpdateProduct(Product instance) {
    this.ExecuteCommand(
       "UPDATE Products SET UnitPrice= UnitPrice *2");
  }
}

den Aktualisierungsprozess selbst festlegen. Die Methode ExecuteCommand des DataContext-Objekts können Sie natürlich auch außerhalb einer partiellen Methode aufrufen.


Galileo Computing - Zum Seitenanfang

29.7.3 Entitätsklassen topZur vorigen Überschrift

Werfen wir nun einen Blick in die vom O/R-Designer erzeugte Entitätsklasse. Diese ist bereits mit dem Table-Attribut verknüpft. Alle spaltenbeschreibenden Eigenschaften weisen das Attribut Column auf, dessen Parameter auf die üblichen Standardwerte eingestellt sind. Möchten Sie diese spezifisch einstellen, ist das im Eigenschaftsfenster am einfachsten. Markieren Sie dazu nur die betreffende Spalte im Designer.

Etwas unglücklich ist die Bezeichnung der Entitätsklasse, die für die Tabelle Products erzeugt wird. Sie heißt so wie die Tabelle, also Products. Inzwischen wissen Sie, dass eine Instanz dieser Klasse einen einzelnen Datensatz abbildet und nicht mehrere, wie man der Pluralisierung entnehmen könnte. Daher sollten Sie Products in Product ändern. Da Sie später häufig eine Liste mehrerer gemappter Datensätze benötigen, können Sie die Liste Products oder products nennen und vermeiden so Irritationen.

Den Bezeichner der Entitätsklasse können Sie im Eigenschaftsfenster ändern. Sie müssen das aber auch bei jeder weiteren Entitätsklasse tun. Eine Alternative ist es, die Vorgabe der Pluralisierung grundsätzlich in Visual Studio zu ändern. Eine solche Einstellungsmöglichkeit gibt es. Sie können sie im Optionen-Dialog vornehmen, den Sie über Extras Optionen öffnen. Wählen Sie aus der linken Liste das Element Datenbanktools aus und anschließend den Eintrag O/R-Designer. Im rechten Bereich des Dialogs wird die Eigenschaft Aktiviert angezeigt, die Sie von False auf True einstellen.

Jede vom O/R-Designer erzeugte Entitätsklasse implementiert mit INotifyPropertyChanging und INotifyPropertyChanging zwei Schnittstellen. Über diese Interfaces werden der Entitätsklasse die beiden Ereignisse PropertyChanging und PropertyChanged aufgezwungen. Entsprechend der üblichen Namenskonvention wird das Ereignis PropertyChanging ausgelöst, ehe ein Feldwert der Entität aktualisiert wird, und PropertyChanged wird ausgelöst, nachdem der Feldwert aktualisiert worden ist. Sie können in Ihrem Code auf die beiden Ereignisse reagieren, wenn Sie im Zusammenhang mit einer Feldaktualisierung noch weitere Operationen ausführen lassen wollen. Sehen wir uns exemplarisch die Definition der Spalte ProductName in der Entitätsklasse an:


public string ProductName {
  get {
    return this._ProductName;
  }
  set {
    if ((this._ProductName != value)) {
      this.OnProductNameChanging(value);
      this.SendPropertyChanging();
      this._ProductName = value;
      this.SendPropertyChanged("ProductName");
      this.OnProductNameChanged();
    }
  }
}

Mit der Anweisung


this._ProductName = value;

wird ein neuer Wert in das Feld ProductName der Entität geschrieben. Ehe die Aktualisierung der Eigenschaft erfolgt, wird mit SendPropertyChanging eine Methode aufgerufen, und direkt nach der Aktualisierung folgt SendPropertyChanged. Diese beiden Methoden kapseln die Ereignisauslösung und prüfen dabei, ob sich ein Abnehmer des Ereignisses registriert hat.


protected virtual void SendPropertyChanging() {
  if ((this.PropertyChanging != null)) {
    this.PropertyChanging(this, emptyChangingEventArgs);
  }
}


protected virtual void SendPropertyChanged(String propertyName) {
  if ((this.PropertyChanged != null)) {
    this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
}

Schauen Sie sich noch einmal den dynamisch erzeugten Code der Spalte ProductName an. Sie werden mit OnProductNameChanging und OnProductNameChanged noch zwei weitere Methoden erkennen. Hierbei handelt es sich um den Aufruf von zwei partiellen Methoden, die in der Entitätsklasse ebenfalls vordefiniert sind.

Da partielle Methoden als Ereignis interpretiert werden können, stellt sich an dieser Stelle die Frage, worin der Unterschied zwischen einer partiellen Methode (beispielsweise OnProductNameChanging) und einem Ereignis (PropertyChanging) besteht?

Implementieren Sie eine partielle Methode, sind alle Komponenten Nutznießer dieses »Ereignisses«. Die zugrunde liegende Entitätsklasse wird also um ein allgemeines Feature erweitert, von dem alle zugreifenden Komponenten profitieren. Ein Ereignis, wie zum Beispiel PropertyChanging, bleibt weiterhin eine Option, die Sie als Entwickler im Einzelfall nutzen können – oder auch nicht.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual C# 2010

Visual C# 2010
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: C/C++






 C/C++


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2010
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern