3 erste schritte mit linq to sql - pearsonerste schritte mit linq to sql 43 wurden mehrere objekte...

31

Upload: others

Post on 31-May-2020

18 views

Category:

Documents


0 download

TRANSCRIPT

3 Erste Schritte mit LINQ to SQL

In diesem Kapitel werden die Möglichkeiten von LINQ toSQL vorgestellt. Anhand lauffähiger Codebeispiele wer-den die CRUD-Datenbankoperationen für das Erstellen,Lesen, Ändern und Löschen von Datensätzen erläutert.

Zum besseren Verständnis der Beispiele sind Kenntnissein Visual Studio und Erfahrungen mit Windows Forms-Projekten unabdinglich.

Architektur und Aufbau des Beispielprojekts sind bezüg-lich Übersichtlichkeit und Verständlichkeit möglichst ein-fach gehalten. Dabei steht nicht die Architektur imVordergrund, es geht viel mehr darum, die Möglichkeitenvon LINQ to SQL aufzuzeigen.

Im Beispiel wird mit einer SQL Server 2005-Instanz undder AdventureWorks-Datenbank gearbeitet. Die Adventure-Works-Datenbank ist die Beispieldatenbank, die mit demSQL Server 2005 mitgeliefert wird. Bei der InstallationIhrer SQL Server 2005-Instanz kann diese Datenbankmitinstalliert werden. Für die nachträgliche Installationfinden Sie den Link zur Beispieldatenbank in Kapitel 1.3»Voraussetzungen für LINQ«.

Um die Beispiele nachzuvollziehen, können Sie auch den SQL Ser-ver 2005 Express Edition verwenden. Bei der Express Edition fehlenjedoch Tools wie SQL Server Management Studio für die Daten-bankverwaltung oder der SQL Server Profiler für die Überwachungder Datenbankaktivitäten. Die übrigen Einschränkungen des SQLServer Express sollten das Beispielprojekt nicht beeinflussen.

TIPP

Kapitel 3

42

3.1 CRUD-Operationen mit LINQ to SQLUnser Beispielprojekt soll zeigen, wie die CRUD-Operationen mithilfe von LINQ toSQL implementiert werden. CRUD steht für Create (Erstellen), Read (Lesen), Update(Ändern) und Delete (Löschen).

Sie werden eine LINQ to SQL Classes-Datei erstellen, welche die Datenbanktabelle Pro-ductCategory als Entity-Klasse visualisiert und im Hintergrund den entsprechendenCode generiert. Gleichzeitig lernen Sie, wie Sie eine Datenbankverbindung aufbauenund wie Sie mit Drag&Drop eine Entity-Klasse Ihrer Datenbanktabelle erstellen.

Nachdem Sie die LINQ to SQL Classes-Datei erstellt haben, ermitteln Sie Datensätze ausder Datenbank. Das DataContext-Objekt übergibt die ermittelten Datensätze an dieProductCategories-Collection. Sobald Sie diese Collection an die DataSource-Eigenschaftdes DataGridView-Control übergeben, werden die Daten im DataGridView-Control auf-gelistet.

Im folgenden Beispiel speichern Sie die Daten mit den Methoden InsertOnSubmit undSubmitChanges in die Datenbanktabelle. Mithilfe einer Lambda Expression werden Sielernen, wie Sie ein bestimmtes Objekt einer Collection ermitteln können. Anschließendändern Sie die Werte dieses Objekts und speichern Sie die Änderungen in der Daten-banktabelle.

Zum Schluss entfernen Sie ein Objekt aus der ProductCategories-Collection. DieseÄnderung wird von der DataContext-Klasse als Datensatzlöschung interpretiert und inder Datenbank wird der Datensatz gelöscht.

Die in diesem Beispiel verwendeten Methoden und ihre Beschreibungen sind:

�  DeleteOnSubmit: DeleteOnSubmit ist eine Methode für Collections von Entity-Objekten, die direkt unter dem DataContext-Objekt vorhanden sind. Mit dieserMethode kann ein bestehendes Entity-Objekt aus der Collection entfernt werden.Mit dem Aufruf der SubmitChanges-Methode wird der entsprechende Datensatzauch in der Datenbanktabelle gelöscht. In Visual Studio 2008 Beta 2 hieß dieseMethode Remove.

�  InsertOnSubmit: InsertOnSubmit ist eine Methode für Collections von Entity-Objek-ten, die direkt unter dem DataContext-Objekt vorhanden sind. Diese Methode fügtder Collection ein neues Objekt hinzu, welches mit dem anschließenden Aufruf derSubmitChanges-Methode auch der Datenbanktabelle hinzugefügt wird. In VisualStudio 2008 Beta 2 hieß diese Methode Add.

�  SubmitChanges: SubmitChanges übergibt veränderte Objekte der entsprechendenDatenbanktabelle. Dabei werden als Erstes die neu hinzugefügten Objekte bearbei-tet, dann erst werden die geänderten Objekte an die Datenbank weitergegeben.

Erste Schritte mit LINQ to SQL

43

Wurden mehrere Objekte geändert, wird im Hintergrund eine Transaktion gestar-tet. Falls alle Objekte erfolgreich an die Datenbanktabellen übergeben wurden,wird die Transaktion geschlossen.

3.1.1 Ein Windows Forms Application-Projekt anlegenFür unser Beispiel benötigen wir ein Windows Forms Application-Projekt. Sie könnendie LINQ to SQL-Funktionalitäten auch mit anderen Projektarten verwenden. Zur bes-seren Darstellung wurde die Projektart Windows Forms Application ausgewählt.

1. Erstellen Sie mit Visual Studio über das Menü FILE/NEW ein neues Windows FormsApplication-Projekt.

Abbildung 3.1: Erstellung eines Visual Studio-Projekts

Kapitel 3

44

2. Definieren Sie als Projektnamen OurBikeStoreUI und als Solution Name OurBikeStore.

3.1.2 LINQ to SQL Classes-Datei erstellenAls Nächstes erstellen Sie ein LINQ to SQL Classes-Element. Mit diesem erhalten Siedie Drag&Drop-Designerunterstützung zur Erstellung der Entity-Klassen. Sie erstelleneine Entity-Klasse, indem Sie eine Datenbanktabelle auf die Designeroberfläche zie-hen. Im Hintergrund generiert Visual Studio den Code für Ihre Datenbankverbindungund für die Entity-Klasse der ausgewählten Datenbanktabelle.

Das LINQ to SQL Classes-Element wird mit der Endung dbml im Projekt gespeichert.

Im Beispiel wird als Datenquelle die Datenbanktabelle ProductCategory der Adventure-Works-Datenbank verwendet. Diese Tabelle beinhaltet die verschiedenen Produktkate-gorien der Adventure Works Cycles-Produkte.

3. Fügen Sie über das Menü PROJEKT/NEUES ELEMENT HINZUFÜGEN oder über Rechts-klick im Solution Explorer-Fenster und HINZUFÜGEN/NEUES ELEMENT dem VisualStudio-Projekt ein neues LINQ to SQL-Element hinzu.

4. Wählen Sie im Fenster NEUES ELEMENT HINZUFÜGEN das LINQ to SQL-Klassenele-ment und definieren Sie als Dateinamen AdventureWorks.dbml.

Abbildung 3.2: Definition Projektname und Solution Name

Erste Schritte mit LINQ to SQL

45

Abbildung 3.3: Hinzufügen eines Visual Studio Projekt-Elements

Abbildung 3.4: Auswahl und Name für Visual Studio Projekt-Elemente

Kapitel 3

46

Anschließend erscheint der grafische Designer für die Entity-Klassen. Innerhalb desO/R-Designers werden die Entity-Klassen mit ihren Verbindungen grafisch darge-stellt. Sie ziehen die gewünschte Datenbanktabelle einfach auf die Designeroberflächeund im Hintergrund generiert Visual Studio den entsprechenden Code der Entity-Klasse. Sie können die verschiedenen Eigenschaften der Entity-Klasse und die einzel-nen Felder der Entity-Klasse über das Eigenschaften-Fenster bearbeiten.

3.1.3 Definieren der DatenbankverbindungWir benötigen eine Verbindung zur AdventureWorks-Datenbank, um die Datenbankta-belle ProductCategory mithilfe von Drag&Drop auf die Designeroberfläche zu ziehen.

5. Definieren Sie im Fenster SERVER-EXPLORER die Verbindung zu Ihrer SQL Server-Instanz. Falls das Server-Explorer-Fenster nicht sichtbar ist, lassen Sie es überANSICHT/SERVER-EXPLORER anzeigen.

Im Fenster SERVER-EXPLORER definieren wir die Verbindungen zu den Datenbanken. Ein-mal definierte Verbindungen können in verschiedenen Projekten verwendet werden.

6. Klicken Sie mit der rechten Maustaste im Server-Explorer auf das Objekt DATEN-VERBINDUNGEN und wählen Sie VERBINDUNG HINZUFÜGEN.

Abbildung 3.5: O/R-Designer zur grafischen Erstellung von Entity-Klassen

Erste Schritte mit LINQ to SQL

47

Abbildung 3.6: Aufruf des Server-Explorer-Fensters zur Datenbankverbindungsdefinition

Abbildung 3.7: Definition der Datenbankverbindung

Kapitel 3

48

7. Als Nächstes geben Sie die Informationen über Ihren SQL Server und Ihre Daten-bank ein. Die AdventureWorks-Datenbank muss installiert sein.

3.1.4 Entity-Klassen durch Drag&Drop erstellenNach erfolgreichem Verbindungsaufbau erscheinen die Datenbankobjekte im SERVER-EXPLORER in Form einer Baumansicht. Unter dem Ordner TABELLEN sind die Daten-banktabellen aufgelistet.

8. Markieren Sie die Datenbanktabelle PRODUCTCATEGORY (PRODUCTION) und ziehenSie diese auf das Designerfenster.

Abbildung 3.8: Verbindungsinformationen SQL Server, Anmeldeinformation und Datenbankname

Nach dem Verbindungsaufbau können Sie das Fenster SERVER-EXPLORER auch als Datenbank-Brow-ser verwenden. Mit einem Rechtsklick auf die einzelnen Datenbankobjekte erhalten Sie – abhängig vomObjekttyp – ein unterschiedliches Kontextmenü mit den wichtigsten Funktionalitäten: das Erstelleneiner neuen Tabelle, das Ändern einer Tabellendefinition, das Erstellen von Abfragen und vieles mehr.

TIPP

Erste Schritte mit LINQ to SQL

49

Abbildung 3.9: Server-Explorer-Fenster mit Datenbankobjekten

Abbildung 3.10: Entity-Klasse im O/R-Designer

Kapitel 3

50

Die Entity-Klasse ProductCategory wird im Designer-Fenster mit den dazugehörendenFeldern visualisiert. Der Primärschlüssel wird mit einem Schlüsselsymbol gekenn-zeichnet.

Wenn Sie mit dem Designer arbeiten, erstellt Visual Studio im Hintergrund den ent-sprechenden Code der Entity-Klasse und legt diesen in der AdventureWorks.dbml-Dateiab.

3.1.5 Windows Forms-Element und Controls erstellenAls Nächstes erstellen wir ein neues Windows Forms-Element zur Anzeige der Product-Category-Daten. Im DataGridView-Control werden die Daten aufgelistet und beimAuswählen einer Zeile wird der entsprechende Dateninhalt in den TextBox CONTROLS

angezeigt.

9. Erstellen Sie ein neues Windows Form über das Menü PROJEKT/WINDOWS FORM

HINZUFÜGEN.

Abbildung 3.11: Anzeige Neues Element hinzufügen-Fenster

Erste Schritte mit LINQ to SQL

51

10. Wählen Sie im Fenster NEUES ELEMENT HINZUFÜGEN das Element WINDOWS FORM

und geben Sie ihm einen Namen.

Auf dem FrmProductCategory werden wir zur Darstellung der Informationen verschie-dene Controls platzieren. Im DataGridView-Control werden die Datensätze aufgelis-tet, die mit dem LOAD-Button aus der Datenbank geladen werden. Beim Auswähleneiner Zeile des DataGridView-Controls werden die Felder ID und Name in den TextBox-Controls angezeigt.

11. Definieren Sie auf Ihrem FrmProductCategory die folgenden Controls und setzen Siedie Eigenschaften auf die Werte in der nachfolgenden Tabelle.

Abbildung 3.12: Erstellung Windows Form

Control Eigenschaft Wert

DataGridView AllowUserToAddRows False

AllowUserToDeleteRows False

Anchor Top, Left, Right

ColumnHeadersHeightSizeMode Autosize

Multiselect False

Name dgvProductCategory

Tabelle 3.1: Eigenschaften und Werte der FrmProductCategory Controls

Kapitel 3

52

ReadOnly True

SelectionMode FullRowSelect

Label Name lblID

Text ID:

Label Name lblName

Text Name:

TextBox Name txtID

ReadOnly True

TextBox Name txtName

ReadOnly True

Abbildung 3.13: FrmProductCategory Form im Designer

Control Eigenschaft Wert

Tabelle 3.1: Eigenschaften und Werte der FrmProductCategory Controls (Fortsetzung)

Erste Schritte mit LINQ to SQL

53

3.1.6 DataContext- und IQueryable-VariableUm die Daten aus der Datenbank zu lesen und an das Entity-Objekt zu übergeben,benötigen wir ein Objekt der DataContext-Klasse. Das DataContext-Objekt lädt dieDaten aus der Datenbank, übergibt diese und liefert die Daten auch wieder an denDatenbankserver zurück.

Für das folgende Beispiel benötigen wir ein DataContext-Objekt vom Typ Adventure-WorksDataContext. Das zusätzlich verwendete Entity-Objekt vom Typ IQueryable<ProductCategory> wird vom DataContext-Objekt mit den aus der Datenbank ermitteltenDaten gefüllt. Diese beiden Objekte definieren wir als private Variablen auf Form-Ebene, damit wir diese in der ganzen FrmProductCategory verwenden können.

12. Wechseln Sie in die Code-Ansicht des FrmProductCategory und definieren Sie eineprivate Variable vom Typ AdventureWorksDataContext. Nennen Sie die Variable _Db.Definieren Sie eine zweite Variable mit dem Namen _ProductCategoryTable vomTyp IQueryable<ProductCategory>.

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;

namespace AdventureWorksUI{ public partial class FrmProductCategory : Form { // Definieren von DataContext-Objekt für die // Verbindung zur Datenbank. // Die _ProductCategoryTable präsentiert die // ProductCategory-Tabelle in diesem Beispiel. AdventureWorksDataContext _Db; IQueryable<ProductCategory> _ProductCategoryTable;

public FrmProductCategory() { InitializeComponent(); } }}

Listing 3.1: Definition der Variablen AdventureWorksDataContext und IQueryable<ProductCategory>

Kapitel 3

54

Durch das Load-Ereignis des FrmProductCategory wird eine neue Instanz der Adventure-WorksDataContext-Klasse erstellt und der _Db-Variablen zugewiesen. Die _Db-Variablewird später für das Laden der Datensätze aus der Datenbank verwendet.

Die Laufzeitverbindungsinformationen zum Datenbankserver werden aus der Dateiapp.config gelesen. Bei der Applikationsweitergabe können die Verbindungsinforma-tionen in der Datei app.config angepasst werden.

Soll die Verbindung zu einem anderen Datenbankserver bzw. einer anderen Daten-bank hergestellt werden, kann beim Instanzieren der DataContext-Klasse ein neuer Con-nectionString an den Konstruktor der DataContext-Klasse übergeben werden.

13. Instanzieren Sie die AdventureWorksDataContext-Klasse im Load-Ereignis des FrmPro-ductCategory und weisen Sie das Objekt der _Db-Variablen zu. Erstellen Sie dasLoad-Ereignis über das Eigenschaften-Fenster.

In der Praxis sollten Sie die Verbindungsinformationen in einer Konfigurationsdatei (.config)ablegen und nicht fix im Code programmieren. Dies ermöglicht die Verwendung unterschiedlicherDatenbankverbindungen ohne Anpassung des Programmcodes.

Abbildung 3.14: Eigenschaften-Fenster mit Ereignisliste des gewählten Controls

TIPP

Erste Schritte mit LINQ to SQL

55

14. Ergänzen Sie das Load-Ereignis für die Instanzierung der AdventureWorksDataCon-text-Klasse und für die Zuweisung an die _Db-Variable wie folgt:

private void FrmProductCategory_Load(object sender, EventArgs e){ // Ein neuer Instanz der AdventureWorksDataContext-Klasse // wird erstellt und an die _Db-Variable zugewiesen. _Db = new AdventureWorksDataContext();}

Listing 3.2: Initialisierung der Klasse AdventureWorksDataContext

3.1.7 Daten aus der Datenbank laden und anzeigenIm nächsten Schritt definieren wir in FrmProductCategory die verschiedenen Buttons.Im Click-Ereignis dieser Buttons werden wir die vier Datenbankoperationen imple-mentieren.

15. Definieren Sie auf Ihrem FrmProductCategory die folgenden Buttons und setzen Siedie Eigenschaften auf die Werte in der Tabelle.

Control Eigenschaft Wert

Button Name btnLoad

Text Load

Button Enabled False

Name btnNew

Text New

Button Enabled False

Name btnEdit

Text Edit

Button Enabled False

Name btnDelete

Text Delete

Button Enabled False

Name btnSave

Text Save

Tabelle 3.2: Die Buttons des FrmProductCategory

Kapitel 3

56

16. Erstellen Sie drei private-Methoden zum Laden der Datensätze aus der Datenbank,zur Anzeige und zum Aktualisieren der Daten.

private void loadDataFromDatabase(){ _ProductCategoryTable = _Db.ProductCategories;}

private void loadDataForDataGridView(){ dgvProductCategory.DataSource = _ProductCategoryTable;}

private void refreshForm(){ loadDataFromDatabase(); loadDataForDataGridView();}

17. Erstellen Sie das Click-Ereignis für den LOAD-Button. In diesem Ereignis wird dierefreshForm-Methode aufgerufen.

Abbildung 3.15: FrmProductCategory im Designer

Erste Schritte mit LINQ to SQL

57

18. Ergänzen Sie den generierten Code wie folgt:

private void btnLoad_Click(object sender, EventArgs e){ refreshForm();}

Listing 3.3: Aufruf der refreshForm()-Methode

Wenn wir eine Zeile im DataGridView-Control markieren, löst das SelectionChanged-Ereignis die Ermittlung der entsprechenden ProductID aus. Mithilfe der Lambda Expres-sion wird der dazugehörende Datensatz aus der Datenbank erneut ausgelesen und demProductCategory-Objekt zugewiesen. Die Eigenschaften des Objekts werden dann zurAnzeige dem TextBox Control übergeben.

Im Folgenden ermitteln wir einen Datensatz aus der Datenbank mithilfe einer LambdaExpression.

Abbildung 3.16: Eigenschaften-Fenster mit Click-Ereignis

Kapitel 3

58

19. Erstellen Sie das SelectionChanged-Ereignis für das DataGridView-Control.

20. Ergänzen Sie anschließend das SelectionChanged-Ereignis mit folgendem Code:

private void dgvProductCategory_SelectionChanged(object sender, EventArgs e){ // Wenn keine Zeile im DataGridView-Control selektiert // ist, dann werden die beiden TextBox Controls-Inhalte // gelöscht. if (dgvProductCategory.SelectedRows.Count != 1) { txtID.Text = String.Empty; txtName.Text = String.Empty;

return; }

// Die ID der selektierten Datensatz wird in eine // Variable gespeichert. Diese Variable wird später // als Filterkriterium verwendet. int productCategoryID = (int)dgvProductCategory

Abbildung 3.17: Eigenschaften-Fenster mit SelectionChanged-Ereignis

Erste Schritte mit LINQ to SQL

59

.SelectedRows[0] .Cells["ProductCategoryID"].Value;

// Mithilfe der Single-Methode wird aus der // ProductCategory-Tabelle ein Datensatz mit einer // bestimmten ID gelesen und das Resultat wird an das // productCategory-Objekt vom Typ ProductCategory // weitergegeben. ProductCategory productCategory = _ProductCategoryTable .Single(pc => pc.ProductCategoryID == productCategoryID);

// Die ID- und Name-Informationen werden aus dem // productCategory-Objekt ausgelesen und an die beiden // TextBox Controls für die Darstellung weitergegeben. txtID.Text = productCategory.ProductCategoryID.ToString(); txtName.Text = producCategory.Name;

txtID.ReadOnly = true; txtName.ReadOnly = true;

btnNew.Enabled = true; btnEdit.Enabled = true; btnDelete.Enabled = true; btnSave.Enabled = false;}

Listing 3.4: Datenbankzugriff für ausgewählten Datensatz mit Übergabe an productCategory-Objekt

Wahl zwischen Single- oder SingleOrDefault-MethodeDie Single-Methode übernimmt das Selektieren eines Datensatzes. Im folgenden Bei-spiel wird ein Datensatz mithilfe einer Lambda-Expression über das DatenbankfeldProductCategoryID ausgewählt.

ProductCategory productCategory = _ProductCategoryTable.Single(pc => pc.ProductCategoryID == productCategoryID);

Die ProductCategoryID ist das Primärschlüsselfeld der Datenbanktabelle ProductCategory.

Die Single-Methode feuert eine Exception, wenn der gesuchte Datensatz in der Pro-ductCategory-Datenbanktabelle nicht existiert.

Verwenden Sie die Single-Methode zusammen mit dem Primärschlüssel, um einen eindeutigenDatensatz zu ermitteln.

TIPP

Kapitel 3

60

ProductCategory productCategory = _ProductCategoryTable.SingleOrDefault(pc => pc.ProductCategoryID == productCategoryID);

Damit können Sie die Existenz des productCategory-Objekts prüfen, bevor Sie auf dasObjekt zugreifen.

3.1.8 ProductCategory Form anzeigenVisual Studio generiert beim Erstellen eines neuen Windows Forms Application-Projektsautomatisch das Form1-Element. Über dieses Form rufen wir das FrmProductCategoryauf.

21. Öffnen Sie Form1 und legen Sie einen Button mit folgenden Eigenschaften an:

22. Definieren Sie das Click-Ereignis für den PRODUCT CATEGORY-Button im Fenster»Eigenschaften«.

Abbildung 3.18: InvalidOperationException beim Zugriff auf nicht vorhandene Datensätze

Verwenden Sie die SingleOrDefault-Methode immer dann, wenn Sie nicht sicher sind, ob einDatensatz in der Datenbank vorhanden ist. Die SingleOrDefault-Methode feuert keine Excep-tion, sondern liefert einen Null-Wert, wenn der Datensatz nicht ermittelt werden kann.

Control Eigenschaft Wert

Button Name btnProductCategory

Text Product Category

Tabelle 3.3: Eigenschaften Product Category-Button

TIPP

Erste Schritte mit LINQ to SQL

61

Abbildung 3.19: Product Category-Button zum Aufruf von FrmProductCategory

Abbildung 3.20: Eigenschaften-Fenster mit Click-Ereignis

Kapitel 3

62

23. Ergänzen Sie das generierte Click-Ereignis für den PRODUCTCATEGORY-Button mit:

private void btnProductCategory_Click(object sender, EventArgs e){ FrmProductCategory frm = new FrmProductCategory(); frm.ShowDialog(this);}

Listing 3.5: Aufruf FrmProductCategory

24. Kompilieren und starten Sie Ihr Projekt nun mit (F5), um – bei erfolgreicher Kom-pilierung – das Form1 und Ihr FrmProductCategory-Form anzuzeigen.

Wenn Sie die Auswahl in der Auflistung ändern, werden beide TextBox-Controlsaktualisiert.

3.1.9 Neuen Datensatz erstellenUm einen neuen Datensatz aus dem Programmcode zu erstellen, definieren wir dasClick-Ereignis für den Button NEW. Dort werden als Erstes die Buttons NEW, EDIT undDELETE deaktiviert und der SAVE-Button aktiviert. Über den SAVE-Button wird dasObjekt dem Datenbankserver zur Speicherung übergeben.

Den beiden TextBox-Controls weisen wir einen leeren String zu und geben dasNamensfeld txtName für die Eingabe frei.

Abbildung 3.21: FrmProductCategory mit Datensatzanzeige

Erste Schritte mit LINQ to SQL

63

25. Erstellen Sie das Click-Ereignis für den Button NEW und ergänzen Sie den Code mitden entsprechenden Anweisungen.

private void btnNew_Click(object sender, EventArgs e){ if (btnNew.Enabled == true) { btnNew.Enabled = false; btnEdit.Enabled = false; btnDelete.Enabled = false btnSave.Enabled = true;

txtID.Text = String.Empty; txtName.ReadOnly = false; txtName.Text = String.Empty; }}

Listing 3.6: Click-Ereignis für den Button New

Um einen neuen Datensatz letztlich in der Datenbanktabelle zu speichern, benötigenwir ein Entity-Objekt zur Übergabe der Daten an das DataContext-Objekt. Deshalberstellen wir als Erstes ein neues ProductCategory-Objekt. Wir weisen die Werte demneuen Objekt zu und fügen das Objekt anschließend mithilfe der Methode InsertOn-Submit der Collection ProductCategories hinzu. Die Methode SubmitChanges übergibtdas neue Objekt an den Datenbankserver.

26. Erstellen und ergänzen Sie das Click-Ereignis des SAVE-Buttons.

private void btnSave_Click(object sender, EventArgs e){ if (txtName.Text.Length == 0) { return; }

if (txtID.Text == string.Empty) { ProductCategory newProductCategory = new ProductCategory(); newProductCategory.Name = txtName.Text; newProductCategory.ModifiedDate = DateTime.Now; newProductCategory.rowguid = Guid.NewGuid();

_Db.ProductCategories.InsertOnSubmit(newProductCategory); }

MessageBox.Show(_Db.GetChangeSet().ToString());

_Db.SubmitChanges();

Kapitel 3

64

btnNew.Enabled = true; btnEdit.Enabled = true; btnDelete.Enabled = true; btnSave.Enabled = false;

txtName.ReadOnly = true;

refreshForm();}

Listing 3.7: Click-Ereignis für Button Save

27. Starten Sie das Projekt mit (F5) und laden Sie die Daten über den Button LOAD.

28. Wählen Sie NEW und geben Sie »Motorbikes« als neuen Product Category-Namenein. Speichern Sie den neuen Datensatz mit SAVE.

Um mit LINQ to SQL einen neuen Datensatz zu erstellen, benötigen wir ein neuesObjekt. Im obigen Beispiel ist das neue Objekt vom Typ ProductCategory, denn es dientzur Aufnahme der Daten für einen neuen Datensatz der Datenbanktabelle Product-Category:

ProductCategory newProductCategory = new ProductCategory();

Die Eigenschaften Name, ModifiedDate und rowGuid des Objekts newProductCatgory ent-sprechen den Datenbankfeldern der Datenbanktabelle ProductCategory und besitzenauch die gleichen Datentypen.

Abbildung 3.22: Neue Product Category »Motorbikes«

Erste Schritte mit LINQ to SQL

65

newProductCategory.Name = txtName.Text;newProductCategory.ModifiedDate = DateTime.Now;newProductCategory.rowguid = Guid.NewGuid();

Wenn wir ein neues Objekt als Datensatz in der Datenbanktabelle speichern möchten,muss dieses Objekt vom DataContext überwacht werden. Um dies zu erreichen, wirddas neue newProductCategory-Objekt – mit der Methode InsertOnSubmit – zur Product-Categories-Collection hinzugefügt, welche ständig vom DataContext überwacht wird.

_Db.ProductCategories.InsertOnSubmit(newProductCategory);

ProductCategories ist eine Collection mit allen ProductCategory-Entity-Objekten, welchezusammen die Datenbanktabelle ProductCategory abbilden. Mit dem hinzugefügtennewProductCategory-Objekt teilen wir dem DataContext-Objekt mit, das neue Objekt beimnächsten SubmitChanges-Methodenaufruf in der Datenbanktabelle als neuen Datensatzzu speichern.

Der Aufruf der SubmitChanges-Methode löst die Übergabe der Objekte an den Daten-bankserver aus. Die DataContext-Klasse erstellt im Hintergrund die zur Übergabe not-wendigen SQL-Anweisungen und gibt diese an die Datenbank weiter.

GetChangeSet-MethodeMit der Methode GetChangeSet ermitteln wir die Änderungen der Objekte, die vomDataContext-Objekt überwacht werden. Im obigen Beispiel wird nach der Speicherungeine MessageBox mit der Anzahl der geänderten Objekte angezeigt. Die GetChangeSet-Methode muss vor der SubmitChanges-Methode aufgerufen werden, da sonst die Ände-rungsinformationen nicht mehr vorhanden sind.

MessageBox.Show("GetChangeSet: " + _Db.GetChangeSet().ToString());

Die MessageBox zeigt ein neues und keine geänderten oder gelöschten Objekte.

Die GetChangeSet-Methode liefert ein ChangeSet-Objekt als Rückgabewert. DiesesObjekt beinhaltet die AddedEntities-, ModifiedEntities- und RemovedEntities-Collec-tion-Eigenschaften, gruppiert nach Änderungsart.

Verwenden Sie die GetChangeSet-Methode als Debugging-Werkzeug, um beispielsweise dieAnzahl der geänderten Objekte zu ermitteln.

Abbildung 3.23: MessageBox zur Anzeige der Änderungsinformationen

TIPP

Kapitel 3

66

�  AddedEntities: Hier werden die neu hinzugefügten Objekte aufgelistet.

�  ModifiedEntities: Hier werden die modifizierten Objekte aufgelistet.

�  RemovedEntitites: Hier werden die gelöschten Objekte aufgelistet.

SubmitChanges-MethodeDie SubmitChanges-Methode gibt die Änderungen über das DataContext-Objekt alsSQL-Anweisungen an den Datenbankserver weiter.

_Db.SubmitChanges();

Der Datenbankserver verarbeitet die vom DataContext generierten SQL-Anweisungenund speichert die Objekte als Datensätze in der Datenbanktabelle ProductCategory.

Nachdem wir mit der Methode SubmitChanges die Daten an das DataContext-Objekt über-geben haben, aktualisieren wir mit der Methode refreshForm die Daten in der Anzeige.Erst jetzt wird unser neuer Eintrag »Motorbikes« im DataGridView aufgelistet.

Abbildung 3.24: ChangeSet-Objekt-Methoden und -Eigenschaften

Abbildung 3.25: FrmProductCategory mit Eintrag Motorbikes

Erste Schritte mit LINQ to SQL

67

3.1.10 Datensatz ändernIn der Collection ProductCategories entspricht jedes Objekt einem Datensatz derDatenbanktabelle. Wenn wir ein Objekt aus der Collection ändern, wird dies mit derSubmitChanges-Methode an den Datenbankserver als Änderung weitergegeben. Dabeigeneriert das DataContext-Objekt die benötigte Update-Anweisung.

Um einen Datensatz zu ändern, definieren wir das Click-Ereignis für den EDIT-Button.Dort deaktivieren wir die Buttons NEW, EDIT und DELETE und aktivieren den SAVE-But-ton, damit die geänderten Werte in die Datenbanktabelle gespeichert werden können.

29. Erstellen Sie das Click-Ereignis für EDIT und ergänzen Sie den Code.

private void btnEdit_Click(object sender, EventArgs e){ if (btnEdit.Enabled == true) { btnNew.Enabled = false; btnEdit.Enabled = false; btnDelete.Enabled = false; btnSave.Enabled = true;

txtName.ReadOnly = false; }}

Nachdem der Product Category-Name geändert und der SAVE-Button geklickt wird,weisen wir den Objekteigenschaften Name und ModifiedDate die neuen Werte zu. Weildas Objekt vom DataContext überwacht wird, merkt sich das DataContext-Objekt dieÄnderung dieser Eigenschaften und markiert das ProductCategory-Objekt in der Col-lection als geändert.

30. Erweitern Sie das Click-Ereignis des SAVE-Buttons.

private void btnSave_Click(object sender, EventArgs e){... if (txtID.Text == string.Empty) { ProductCategory newProductCategory = new ProductCategory(); newProductCategory.Name = txtName.Text; newProductCategory.ModifiedDate = DateTime.Now; newProductCategory.rowguid = Guid.NewGuid();

_Db.ProductCategories.InsertOnSubmit(newProductCategory); } else

Kapitel 3

68

{ ProductCategory productCategory = _ProductCategoryTable.Single(pc => pc.ProductCategoryID == Convert.ToInt32(txtID.Text)); productCategory.Name = txtName.Text; productCategory.ModifiedDate = DateTime.Now; }

MessageBox.Show(_Db.GetChangeSet().ToString());

_Db.SubmitChanges();

...}

Listing 3.8: Click-Ereignis für den Button Save

31. Starten Sie das Projekt mit (F5) und laden Sie mit LOAD die Daten aus der Daten-bank auf Ihr FrmProductCategory. Markieren Sie anschließend den Eintrag »Motor-bikes« und ändern Sie den Namen in »Quad«.

32. Speichern Sie den Datensatz mit SAVE in der Datenbanktabelle.

Die folgende MessageBox zeigt die Anzahl geänderter Objekte aus unserem Beispiel.

Abbildung 3.26: FrmProductCategory mit Datensatzänderung

Erste Schritte mit LINQ to SQL

69

Die Anzeige wird erst nach Bestätigen der MessageBox aktualisiert. Danach erscheintauch der Eintrag »Quad« in der Liste.

3.1.11 Datensatz löschenWas uns noch fehlt, ist das Löschen der Daten in der Datenbanktabelle. Dies basiert aufdem gleichen Prinzip wie eine Datenänderung. Es können nur Objekte gelöscht wer-den, die vom DataContext-Objekt überwacht werden.

Als Erstes ermitteln wir dabei die Objektdaten aus der Collection und löschen dieDaten anschließend mit der Methode DeleteOnSubmit aus der Collection. Dadurch wirddas Objekt in der Collection als gelöscht markiert. Beim nächsten Aufruf der Sub-mitChanges-Methode generiert das DataContext-Objekt die benötigte Delete-Anweisungund leitet diese an den Datenbankserver weiter.

33. Ergänzen Sie das Click-Ereignis des DELETE-Button.

Abbildung 3.27: MessageBox mit Anzahl geänderter Objekte

Abbildung 3.28: FrmProductCategory mit geändertem Eintrag (Quad statt Motorbikes)

Kapitel 3

70

private void btnDelete_Click(object sender, EventArgs e){ if (txtID.Text.Length == 0) { return; }

ProductCategory productCategory = _ProductCategoryTable.Single(pc => pc.ProductCategoryID == Convert.ToInt32(txtID.Text));

_Db.ProductCategories.DeleteOnSubmit(productCategory);

MessageBox.Show(_Db.GetChangeSet().ToString());

_Db.SubmitChanges();

btnNew.Enabled = true; btnEdit.Enabled = true; btnDelete.Enabled = true; btnSave.Enabled = false;

txtName.ReadOnly = true;

refreshForm();}

Listing 3.9: Click-Ereignis für den Button DELETE

34. Starten Sie das Projekt mit (F5) und laden Sie Daten aus der Datenbank. MarkierenSie den Quad-Eintrag und löschen Sie ihn.

Die MessageBox zeigt ein gelöschtes Objekt.

Die Anzeige wird erst nach Bestätigung der MessageBox aktualisiert. Der Quad-Ein-trag erscheint nicht mehr in der Liste.

Abbildung 3.29: MessageBox mit Anzahl gelöschter Objekte