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

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 35 ADO.NET – Aktualisieren der Datenbank
Pfeil 35.1 Aktualisieren mit dem »CommandBuilder«
Pfeil 35.1.1 Die von »SqlCommandBuilder« generierten Aktualisierungsstatements
Pfeil 35.1.2 Konfliktsteuerung in einer Mehrbenutzerumgebung
Pfeil 35.1.3 Die Eigenschaft »ConflictOption« des »SqlCommandBuilders«
Pfeil 35.1.4 Die Eigenschaft »SetAllValues«
Pfeil 35.2 Manuell gesteuerte Aktualisierung
Pfeil 35.2.1 Eigene Aktualisierungslogik
Pfeil 35.2.2 Das Beispielprogramm
Pfeil 35.3 Konfliktanalyse
Pfeil 35.3.1 Den Benutzer über fehlgeschlagene Aktualisierungen informieren
Pfeil 35.3.2 Konfliktverursachende Datenzeilen bei der Datenbank abfragen
Pfeil 35.4 Neue Autoinkrementwerte abrufen

Rheinwerk Computing - Zum Seitenanfang

35.2 Manuell gesteuerte AktualisierungZur nächsten Überschrift

Mit komplexen Aktualisierungsszenarien kann der SqlCommandBuilder nicht umgehen. Er scheidet in solchen Fällen aus und muss durch manuellen Aktualisierungscode ersetzt werden. Wir können dazu durchaus auf das SqlDataAdapter-Objekt und dessen Update-Methode zurückgreifen. Den Aktualisierungscode, den uns in einfacheren Umgebungen der SqlCommandBuilder zur Verfügung stellt, müssen wir allerdings selbst schreiben.

Grundsätzlich ist bei der Aktualisierung mit der Update-Methode des SqlDataAdapters entscheidend, dass die Eigenschaften

  • UpdateCommand
  • InsertCommand
  • DeleteCommand

des SqlDataAdapters ein passendes SqlCommand-Objekt beschreiben. Die Update-Methode arbeitet im Grunde genommen sehr einfach. Sie sucht in einem DataSet bzw. in der DataTable nach den Datenzeilen, deren DataRowState nicht Unchanged ist. Trifft die Methode auf eine in welcher Weise auch immer geänderte Datenzeile, greift sie auf ein entsprechendes Command-Objekt zurück, weist die entsprechenden Parameter zu und setzt die Änderung ab.

Der entscheidende Punkt ist, dass der DataAdapter sich nicht dafür interessiert, wie das Command-Objekt gestaltet ist und aus welcher Quelle es stammt. Wichtig ist ihm nur, dass ein gültiges Command-Objekt vorliegt. Damit haben wir auch schon den ersten Ansatz gefunden. Wir stellen eigene Command-Objekte zur Verfügung, nennen wir sie updateCommand, deleteCommand und insertCommand, und weisen sie den entsprechenden Eigenschaften des DataAdapters zu:

<SqlDataAdapter>.UpdateCommand = updateCommand;
<SqlDataAdapter>.InsertCommand = insertCommand;
<SqlDataAdapter>.DeleteCommand = deleteCommand;

Alle drei Eigenschaften sind vom Typ SqlCommand. Ein Command-Objekt kennt durch seine Eigenschaft CommandText das SQL-Kommando, das gegen die Datenbank abgesetzt werden soll. Damit sind alle Forderungen, welche die Methode Update des DataAdapters stellt, erfüllt.

Etwas erleichtern können wir uns das manuelle Aktualisieren, wenn wir daran denken, dass meistens keine besonderen Anforderungen sowohl hinsichtlich des Einfügens einer neuen Datenzeile als auch des Löschens einer Datenzeile gestellt werden. Hier leistet der SqlCommandBuilder dann oft sehr gute Dienste, um das entsprechende INSERT- und DELETE-Statement zu erzeugen. Sie müssen in diesen Fällen nur ein SqlCommand-Objekt bereitstellen, das den Aktualisierungsanforderungen an eine geänderte Datenzeile entspricht, und dieses der Eigenschaft UpdateCommand des SqlDataAdapters übergeben.


Rheinwerk Computing - Zum Seitenanfang

35.2.1 Eigene AktualisierungslogikZur nächsten ÜberschriftZur vorigen Überschrift

Den folgenden Ausführungen liegt das folgende SQL-Statement zugrunde:

SELECT ProductID, ProductName, Unitprice, UnitsInStock, Discontinued 
FROM Products

Sehen wir uns nun die Methode an, die für das Erzeugen des Kommandos zum Absetzen einer Datenzeilenänderung verantwortlich ist. Auch bei dieser Methode sei angenommen, dass zwischenzeitliche Änderungen durch andere Benutzer bei der Aktualisierung überschrieben werden. Dabei sei gefordert, dass etwaige Änderungen eines anderen Benutzers in der Spalte ProductName und UnitPrice nicht akzeptiert werden können und zu einem Konflikt führen sollen. Im Suchkriterium ist daher die Angabe des Primärschlüssels und des Originalwertes der Spalten ProductName und UnitPrice erforderlich.

static SqlCommand CreateUpdateCommand(SqlConnection con) {
string sql = "UPDATE Products SET ProductName=@p1, UnitPrice=@p2, UnitsInStock=@p3
WHERE ProductID=@p4 AND ProductName= @p5 AND UnitPrice=@p6";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.Add("@p1", SqlDbType.VarChar, 40, "ProductName");
cmd.Parameters.Add("@p2", SqlDbType.Money, 8, "UnitPrice");
cmd.Parameters.Add("@p3", SqlDbType.SmallInt, 2, "UnitsInStock");
cmd.Parameters.Add("@p4", SqlDbType.Int, 4, "ProductID");
SqlParameter param;
param = cmd.Parameters.Add("@p5", SqlDbType.VarChar, 40, "ProductName");
param.SourceVersion = DataRowVersion.Original;
param = cmd.Parameters.Add("@p6", SqlDbType.Money, 8, "UnitPrice");
param.SourceVersion = DataRowVersion.Original;
return cmd
}

Listing 35.3 Manuell erstelltes UPDATE-Statement

Wird der DataAdapter zur Aktualisierung eingesetzt, muss jedem Parameter mitgeteilt werden, aus welcher Spalte der zu editierenden DataRow der Wert für den betreffenden Parameter abgerufen werden soll, beispielsweise:

cmd.Parameters.Add("@p1", SqlDbType.VarChar, 40, "ProductName");

Hier teilen wir dem Parameter mit, dass er den Wert aus der Spalte ProductName beziehen soll. Standardmäßig wird der Wert aus DataRowVersion.Current bezogen. Vergessen Sie die Angabe des vierten Parameters, kann der DataAdapter die Datenzeile nicht an die Datenbank übermitteln. Haben Sie eine explizite Referenz auf den Parameter, können Sie die Spalte auch der Eigenschaft SourceColumn bekannt geben.

Die Parameter der Suchkriterien benötigen den Originalwert, um die betreffende Datenzeile in der Tabelle der Datenbank aufzuspüren. Damit der DataAdapter die erforderlichen Werte aus DataRowVersion.Original einträgt, teilen Sie das dem Parameter in seiner Eigenschaft SourceVersion mit:

param.SourceVersion = DataRowVersion.Original;

Das auf diese Weise in der Methode erzeugte Command-Objekt wird an den Aufrufer zurückgeliefert. Wie Sie weiter oben schon gesehen haben, weisen wir dessen Referenz der Eigenschaft UpdateCommand des DataAdapters zu, der automatisch die Parameter füllt, wenn er auf eine geänderte Datenzeile trifft.

Die Primärschlüsselspalte ProductID stellt hierbei in der Tabelle Products einen Sonderfall dar, da sie als Autoinkrementspalte definiert ist und somit grundsätzlich nicht verändert werden kann. Somit entfällt für diese Spalte die Notwendigkeit, den Wert der Originalversion abzufragen.


Rheinwerk Computing - Zum Seitenanfang

35.2.2 Das BeispielprogrammZur vorigen Überschrift

Planen Sie eine eigene Aktualisierungslogik, unterscheidet sich der Programmcode kaum von dem, den Sie auch unter Benutzung des CommandBuilders schreiben würden. Wir wollen im nächsten Beispiel die Methode CreateUpdateCommand testen und dabei auf die Dienste des SqlCommandBuilders nicht vollständig verzichten. Denn wie bereits weiter oben erwähnt, können die von diesem Objekt erzeugten Command-Objekte zum Löschen oder Hinzufügen einer Datenzeile durchaus verwendet werden, weil an diese Vorgänge in der Regel keine besonderen Anforderungen gestellt werden.

// Beispiel: ..\Kapitel 35\ManuelleAktualisierung
static void Main(string[] args) {
SqlConnection con = new SqlConnection();
con.ConnectionString = "...";
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SELECT ProductID, ProductName, Unitprice, UnitsInStock,
Discontinued FROM Products";
cmd.Connection = con;
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
SqlCommandBuilder cmb = new SqlCommandBuilder(da);
da.UpdateCommand = CreateUpdateCommand(con);
da.FillSchema(ds, SchemaType.Source);
ds.Tables[0].Columns[0].AutoIncrementSeed = -1;
ds.Tables[0].Columns[0].AutoIncrementStep = -1;
da.Fill(ds);
// Datenzeilen ändern
ChangeDataRows(ds);
// Datenzeilen hinzufügen
AddDataRows(ds);
// Simulation eines Konflikts
Console.Write("Konflikt simulieren ...");
Console.ReadLine();
// Datenbank aktualisieren
da.Update(ds);
Console.WriteLine("Datenbank ist aktualisiert.");
Console.ReadLine();
}
static void ChangeDataRows(DataSet ds){
ds.Tables[0].Rows[0]["ProductName"] = "Pfeffer";
ds.Tables[0].Rows[1]["Productname"] = "Salz";
ds.Tables[0].Rows[2]["Productname"] = "Banane";
ds.Tables[0].Rows[3]["Productname"] = "Orange";
ds.Tables[0].Rows[4]["Productname"] = "Mango";
ds.Tables[0].Rows[5]["UnitsInStock"] = 125;
ds.Tables[0].Rows[6]["UnitsInStock"] = 55;
}
static void AddDataRows(DataSet ds) {
DataRow row1 = ds.Tables[0].NewRow();
row1["Productname"] = "Suppenhuhn";
row1["Discontinued"] = 0;
ds.Tables[0].Rows.Add(row1);
DataRow row2 = ds.Tables[0].NewRow();
row2["Productname"] = "Aachener Printe";
row2["Discontinued"] = 0;
ds.Tables[0].Rows.Add(row2);
}

Listing 35.4 Manuelles Aktualisieren

Die Methoden ChangeDataRows und AddDataRows beschreiben die an der Tabelle Products vorgenommenen Änderungen. Es werden insgesamt sieben Datenzeilen editiert: Fünf Änderungen betreffen die Spalte ProductName, zwei die Spalte UnitsInStock. Darüber hinaus werden zwei weitere Datenzeilen zur Tabelle hinzugefügt.

In Main werden dem DataAdapter die Aktualisierungsstatements zugewiesen. Um neue Datenzeilen hinzuzufügen, ohne dafür eine eigene Methode schreiben zu müssen, wird der SqlCommandBuilder bemüht. Anschließend erfolgt der Aufruf der Methode CreateUpdateCommand, um die manuelle Aktualisierungslogik editierter Datenzeilen durchzusetzen.

Erscheint zur Laufzeit die Meldung »Konflikt simulieren« an der Konsole, können Sie das Konfliktverhalten testen. Öffnen Sie dazu beispielsweise den Server-Explorer, und stellen Sie eine Verbindung zu der betreffenden Datenbank Northwind her. Öffnen Sie danach die Tabelle Products, und ändern Sie in einem der ersten fünf Datensätze den Lagerbestand. Setzen Sie danach die Ausführung des Beispielprogramms fort, wird am Ende die erfolgreiche Aktualisierung angezeigt.

Eine Änderung in der Spalte ProductName hingegen wird bei einem solchen Test zu einer Ausnahme vom Typ DBConcurrencyException führen, die einen Parallelitätskonflikt signalisiert. Das angestrebte Ziel wäre somit erreicht: Wir verursachen einen Konflikt, wenn zwei Anwender in der Spalte ProductName (und natürlich auch UnitPrice) derselben Datenzeile eine sich überschneidende Änderung vornehmen.



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual C# 2012

Visual C# 2012
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
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