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

Inhaltsverzeichnis
1 Einführung
2 Grundlagen der Sprachsyntax
3 Klassendesign
4 Weitere Datentypen
5 Multithreading
6 Collections und LINQ
7 Eingabe und Ausgabe
8 Anwendungen: Struktur und Installation
9 Code erstellen und debuggen
10 Einige Basisklassen
11 Windows-Anwendungen erstellen
12 Die wichtigsten Steuerelemente
13 Tastatur- und Mausereignisse
14 MDI-Anwendungen
15 Grafiken mit GDI+
16 Drucken
17 Entwickeln von Steuerelementen
18 Programmiertechniken
19 WPF – Grundlagen
20 Layoutcontainer
21 WPF-Steuerelemente
22 Konzepte von WPF
23 Datenbankverbindung mit ADO.NET
24 Datenbankabfragen mit ADO.NET
25 DataAdapter
26 Offline mit DataSet
27 Datenbanken aktualisieren
28 Stark typisierte DataSets
A Anhang: Einige Übersichten
Stichwort

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual Basic 2008 von Andreas Kuehnel, Stephan Leibbrandt
Das umfassende Handbuch
Buch: Visual Basic 2008

Visual Basic 2008
3., aktualisierte und erweiterte Auflage, geb., mit DVD
1.323 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1171-0
Pfeil 26 Offline mit DataSet
Pfeil 26.1 Das DataSet-Objekt verwenden
Pfeil 26.1.1 Ein DataSet-Objekt erzeugen
Pfeil 26.1.2 Anatomie einer DataTable
Pfeil 26.1.3 Zugriff auf eine Tabelle im DataSet
Pfeil 26.1.4 Zugriff auf die Ergebnisliste
Pfeil 26.1.5 Dateninformationen in eine XML-Datei schreiben
Pfeil 26.2 DataSet mit Schemainformationen
Pfeil 26.2.1 Schemainformationen bereitstellen
Pfeil 26.2.2 Gültigkeitsprüfung in einer DataColumn
Pfeil 26.2.3 Constraints-Klassen einer DataTable
Pfeil 26.2.4 Tabellenschema durch Programmcode
Pfeil 26.2.5 Tabellenschema durch DataAdapter
Pfeil 26.2.6 Tabellenschema aus einer XML-Datei
Pfeil 26.3 Änderung einer Tabelle
Pfeil 26.3.1 Editieren einer Datenzeile
Pfeil 26.3.2 Löschen einer Datenzeile
Pfeil 26.3.3 Neue Datenzeile hinzufügen
Pfeil 26.4 Änderung einer Datenzeile
Pfeil 26.4.1 Aktualisierungszustand
Pfeil 26.4.2 Ursprünglicher und aktualisierter Inhalt
Pfeil 26.4.3 Zeilenstatus manuell steuern
Pfeil 26.5 Mit mehreren Tabellen arbeiten
Pfeil 26.5.1 JOIN-Abfragen
Pfeil 26.5.2 Mehrere Tabellen in einem DataSet
Pfeil 26.5.3 Tabellenbeziehungen erzeugen
Pfeil 26.5.4 DataRelations und Einschränkungen
Pfeil 26.5.5 In Beziehung stehende Daten suchen
Pfeil 26.5.6 Ergänzung zum Speichern von Schemainformationen in einer XML–Schemadatei
Pfeil 26.6 Suchen und Filtern
Pfeil 26.6.1 Find
Pfeil 26.6.2 Select
Pfeil 26.7 Objekte vom Typ DataView
Pfeil 26.7.1 Initialisierung
Pfeil 26.7.2 Zugriff auf die Datenzeilen
Pfeil 26.7.3 Spalten durchsuchen
Pfeil 26.7.4 Mehrdeutige Suchergebnisse
Pfeil 26.7.5 Datenfilter
Pfeil 26.7.6 Statusfilter
Pfeil 26.7.7 Änderungen
Pfeil 26.7.8 DataView in DataTable umwandeln


Rheinwerk Computing - Zum Seitenanfang

26.3 Änderung einer Tabelle Zur nächsten ÜberschriftZur vorigen Überschrift

Sehen wir uns nun an, wie wir einer DataTable eine neue DataRow hinzufügen, eine vorhandene löschen bzw. editieren können. Um einen wichtigen Punkt gleich vorwegzunehmen: Jegliche Änderung betrifft zunächst nur das DataSet. Die Originaldatenbank weiß davon nichts. Erst zu einem späteren Zeitpunkt werden alle Änderungen zur Datenbank übermittelt. Wir behandeln in diesem Abschnitt nur die lokalen Aktualisierungen.


Rheinwerk Computing - Zum Seitenanfang

26.3.1 Editieren einer Datenzeile Zur nächsten ÜberschriftZur vorigen Überschrift

Es gibt drei Möglichkeiten, eine Zeile zu aktualisieren. Im einfachsten Fall weisen Sie der betreffenden Spalte nur den neuen Inhalt zu, zum Beispiel:

ds.Tables(0).Rows(3)("ProductName") = "Kirschkuchen"

Die Änderung wird sofort in die angegebene Spalte der entsprechenden Datenzeile der DataTable geschrieben.

Eine zweite Variante puffert die Änderung. Dazu wird vor Beginn der Änderung die Methode BeginEdit auf der zu ändernden Datenzeile aufgerufen und die Änderung mit EndEdit bestätigt. Sie können die eingeleitete Änderung auch zurücksetzen und anstelle von EndEdit die Methode CancelEdit aufrufen. Die Zeile wird dann in den Zustand zurückversetzt, den sie vor BeginEdit hatte.

Dim row As DataRow = ds.Tables(0).Rows(3) 
row.BeginEdit() 
row("ProductName") = "Kirschkuchen" 
row.EndEdit() 
' alternativ: row.Canceledit()

Die dritte Möglichkeit bietet uns die Eigenschaft ItemArray, mit der Sie den Inhalt einer Datenzeile abrufen oder verändern können. ItemArray arbeitet mit einem Array, in dem jedes Element einer Spalte entspricht. Mit einer Codezeile können Sie mehrere Spaltenwerte abrufen und editieren. Ist in einer Zeile nur eine Teilmenge der verfügbaren Werte zu modifizieren, verwenden Sie Nothing, um anzuzeigen, dass der Wert dieser Spalte nicht geändert werden soll. Jedes Element ist vom Typ Object.

Im folgenden Codefragment werden drei Spalten der Products-Tabelle abgefragt. In der ersten Datenzeile wird mit der Eigenschaft ItemArray der Produktbezeichner modifiziert. Weil der Schlüsselwert nicht geändert wird, muss an der ersten Position Nothing in das Objekt-Array geschrieben werden.

Dim cmd As DbCommand = new SqlCommand() 
cmd.Connection = con 
cmd.CommandText = "SELECT ProductID, ProductName, UnitPrice FROM Products" 
Dim ds As DataSet = New DataSet() 
Dim da As DbDataAdapter = New SqlDataAdapter(cmd) 
da.Fill(ds) 
Dim row As DataRow = ds.Tables(0).Rows(0) 
row.ItemArray = New Object() {Nothing, "Kirschkuchen"}

NULL-Spaltenwert

Möchten Sie den Wert einer Spalte auf NULL setzen, verwenden Sie die Klasse DBNull, die sich im Namespace System befindet. Mit der Eigenschaft Value legen Sie den Wert einer Spalte in einer DataRow auf NULL fest:

Dim row As DataRow = ds.Tables(0).Rows(4) 
row("UnitPrice") = DBNull.Value

Ereignisse bei der Änderung einer Datenzeile

Die DataTable verfügt über mehrere Ereignisse, die in Tabelle 26.4 aufgelistet sind.


Tabelle 26.4 Ereignisse beim Ändern einer Datenzeile

Ereignis Auslösung

RowChanging

Vor dem Eintragen der Änderung an einer Datenzeile in das DataSet

RowChanged

Nach dem Eintragen der Änderung an einer Datenzeile in das DataSet

ColumnChanging

Vor dem Eintragen der Änderung in einer Spalte in das DataSet

ColumnChnaged

Nach dem Eintragen der Änderung in einer Spalte in das DataSet


Die Ereignisse spielen eine Rolle, wenn Änderungen an einer Datenzeile oder Spalte überprüft werden müssen. Sie werden nicht ausgelöst, wenn Sie CancelEdit aufrufen.

Die Ursache für die Ereignisse RowChanging und RowChanged können Sie mittels der Eigenschaft Action des DataRowChangeEventArgs-Parameters abfragen. Sie kann die Werte Nothing, Delete, Change, Rollback, Commit, Add, ChangeOriginal und ChangeCurrentAndOriginal annehmen. Mit der Eigenschaft Row des Parameters erhalten Sie zudem die Referenz auf die auslösende Datenzeile.

Die Ereignisse ColumnChanging und ColumnChanged liefern im Parameter DataColumnChangeEventArgs in der Eigenschaft Row ebenfalls die Referenz auf die zu ändernde bzw. geänderte Datenzeile, die Eigenschaft Column liefert darüber hinaus die Referenz auf die geänderte Spalte. Den neuen Wert können Sie der Eigenschaft ProposedValue entnehmen.

Das Beispiel Ereignisse registriert vier Ereignishandler, die durch die nachfolgende Zuweisung angesprochen werden:


'...\ADO\DataSet\Ereignisse.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module Ereignisse 
    Sub Test() 
      Dim con As DbConnection = New SqlConnection() 
      con.ConnectionString = "Data Source=(local);" & _ 
          "Initial Catalog=Northwind;Integrated Security=sspi" 
      Dim cmd As DbCommand = New SqlCommand() 
      cmd.CommandText = "SELECT Top 2 ProductID, ProductName FROM Products" 
      cmd.Connection = con

      Dim ds As New DataSet() 
      Dim da As DbDataAdapter = New SqlDataAdapter() 
      da.SelectCommand = cmd 
      da.Fill(ds)

      AddHandler ds.Tables(0).ColumnChanging, AddressOf Spalte 
      AddHandler ds.Tables(0).ColumnChanged, AddressOf Spalte 
      AddHandler ds.Tables(0).RowChanging, AddressOf Zeile 
      AddHandler ds.Tables(0).RowChanged, AddressOf Zeile 
      ds.Tables(0).Rows(0)("ProductName") = "Tee"

      Console.ReadLine() 
    End Sub

    Sub Zeile(ByVal sender As Object, ByVal ev As DataRowChangeEventArgs) 
      Console.WriteLine("Zeilenaktion: {0}", ev.Action) 
      Console.WriteLine("Wert: {0}", ev.Row("ProductName")) 
    End Sub

    Sub Spalte(ByVal sender As Object, ByVal ev As DataColumnChangeEventArgs) 
      Console.WriteLine("Spalte: {0}", ev.Column.ColumnName) 
      Console.WriteLine("Neuer Wert: {0}", ev.ProposedValue) 
      Console.WriteLine("Wert: {0}", ev.Row("ProductName")) 
    End Sub 
  End Module 
End Namespace

Die Ausgabe zeigt, dass die Spaltenänderung abgeschlossen wird, bevor die Zeilenänderung behandelt wird:

Spalte: ProductName 
Neuer Wert: Tee 
Wert: Alice Mutton

Spalte: ProductName 
Neuer Wert: Tee 
Wert: Tee

Zeilenaktion: Change 
Wert: Tee

Zeilenaktion: Change 
Wert: Tee

Rheinwerk Computing - Zum Seitenanfang

26.3.2 Löschen einer Datenzeile Zur nächsten ÜberschriftZur vorigen Überschrift

Zum Löschen einer Datenzeile rufen Sie einfach Delete auf der zu löschenden DataRow auf:

row.Delete()

Die Datenzeile ist nicht aus der DataTable entfernt, sondern ADO.NET kennzeichnet sie als gelöscht. Der Hintergrund der Markierung ist, dass das Löschen zunächst nur das aktuelle DataSet betrifft und zu einem späteren Zeitpunkt der Originaldatenbank mitgeteilt werden muss. Es ist daher auch falsch, eine Datenzeile mit Remove oder RemoveAt aus der DataRow-Collection der Tabelle zu entfernen, denn dann findet der Aktualisierungsprozess die Datenzeile nicht mehr.

Auch beim Löschen treten zwei Ereignisse auf: RowDeleting und RowDeleted. Beide verwenden die gleichen Eigenschaften und Argumente wie RowChanging und RowChanged.


Rheinwerk Computing - Zum Seitenanfang

26.3.3 Neue Datenzeile hinzufügen topZur vorigen Überschrift

Eine Datenzeile zu einer DataTable hinzuzufügen, ist nicht schwierig. Allerdings stellt die Klasse DataRow keinen öffentlichen Konstruktor zur Verfügung, denn woher sollte ein auf diese Weise konstruiertes DataRow-Objekt etwas von den Spalten wissen, die es beschreibt?

ADO.NET bietet Ihnen analog zum Editieren einer Datenzeile drei Varianten an, um eine neue Datenzeile zu einer DataTable hinzuzufügen. Eine mit der Methode NewRow der DataTable erzeugte Zeile enthält alle Informationen über die Spalten in der Tabelle. Wenn im Schema keine Standardwerte vorgegeben werden, sind die Inhalte der Spalten auf NULL gesetzt. Haben Sie alle Einträge in der neuen Zeile vorgenommen, müssen Sie die neue Zeile an die DataRowCollection anhängen, denn das leistet der Aufruf von NewRow nicht.

Dim tbl As DataTable = ds.Tables(0) 
Dim row As DataRow = tbl.NewRow() 
row("ProductName") = "Erbsensuppe" 
row("UnitPrice") = 2 
row("SupplierID") = 3 
' ... 
tbl.Rows.Add(row)

Eine Überladung der Methode Add der DataRowCollection ist die zweite Variante zur Erzeugung neuer Zeilen. Übergeben Sie dem Methodenaufruf die Spaltenwerte in derselben Reihenfolge wie in der SELECT-Abfrage. Basierend auf der Auswahlabfrage

SELECT ProductName, Unitprice, UnitsInStock FROM Products

könnte eine neue Datenzeile wie folgt hinzugefügt werden:

ds.Tables(0).Rows.Add("Mehl", 20)

Im Gegensatz zur Methode NewRow wird die neue Datenzeile automatisch der DataRowCollection hinzugefügt.

Die dritte Möglichkeit ist die Methode LoadDataRow der DataTable. Sie arbeitet ähnlich wie die zuvor gezeigte Add-Methode der DataRowCollection, verlangt aber die Angabe von zwei Parametern. Geben Sie im ersten Parameter ein Array von Werten an, dessen Elemente den Spalten in der Tabelle entsprechen. Tragen Sie im zweiten Parameter False ein, um die so gekennzeichnete Datenzeile als neue Datenzeile zu interpretieren. Der Wert True ermöglicht es, eine bestimmte Datenzeile zu suchen und zu modifizieren.

ds.Tables(0).LoadDataRow(New Object() {"Mehl", 20, 0}, False)

Sonderfall: Autoinkrementspalten

Viele Tabellen in Datenbanken besetzen das Primärschlüsselfeld mit Autoinkrementwerten. Diese garantieren automatisch, dass alle Einträge einmalig sind. Fügen wir jedoch eine neue Datenzeile zu einer DataTable hinzu, die ein solches Schlüsselfeld definiert, haben wir keine Verbindung zur Originaldatenbank, sodass wir den neuen Wert des Schlüsselfeldes nicht kennen, bis wir die Datenbank aktualisieren und die Datenbankwerte erneut abfragen.

ADO.NET unterstützt uns mit drei Eigenschaften der DataColumn, um auch diese scheinbare Problematik zu lösen:

  • AutoIncrement
  • AutoIncrementSeed
  • AutoIncrementStep

Um in einer DataTable Autoinkrementwerte von ADO.NET generieren zu lassen, muss die Eigenschaft AutoIncrement der betreffenden Spalte auf True gesetzt werden. Mit AutoIncrementSeed und AutoIncrementStep werden die von ADO.NET erzeugten Werte gesteuert. AutoIncrementSeed beschreibt den Startwert für die erste neu hinzugefügte Datenzeile. AutoIncrementStep gibt die Schrittweite an, mit der neue Schlüsselwerte generiert werden. Zum Beispiel erzeugt eine Autoinkrementspalte mit AutoIncrementSeed=1 und AutoIncrementStep=2 die Werte 1, 3 und 5 in der Autoinkrementspalte für die drei nächsten hinzugefügten Datenzeilen.

Die Werte, die ADO.NET erzeugt, sind nur Platzhalter. Sie werden später bei der Aktualisierung der Originaldatenbank nicht mit zurückgeschrieben. Die tatsächlichen Schlüsselwerte erzeugt die Datenbank selbst. Sie müssen sicherstellen, dass neue Schlüsselwerte nicht mit den alten in Konflikt geraten. Meistens verwenden Datenbanken keine negativen Werte, sodass die Festlegung der beiden Eigenschaften AutoIncrementSeed und AutoIncrementStep auf jeweils -1 ein guter Ausgangspunkt ist. Diese Einstellungen müssen erfolgen, ehe das DataSet mit den Daten gefüllt wird. Im folgenden Beispiel ist der Rahmen gezeigt:


'...\ADO\DataSet\AutoInkrement.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module AutoInkrement 
    Sub Test() 
      Dim con As DbConnection = New SqlConnection() 
      con.ConnectionString = "Data Source=(local);" & _ 
          "Initial Catalog=Northwind;Integrated Security=sspi" 
      Dim cmd As DbCommand = New SqlCommand() 
      cmd.Connection = con 
      Dim da As DbDataAdapter = New SqlDataAdapter() 
      Dim ds As DataSet = Create(cmd, da)

      Dim row As DataRow, tbl As DataTable = ds.Tables(0) 
      row = tbl.NewRow() : row("ProductName") = "Saft" : tbl.Rows.Add(row) 
      row = tbl.NewRow() : row("ProductName") = "Limo" : tbl.Rows.Add(row) 
      Dim cb As DbCommandBuilder = New SqlCommandBuilder() 
      cb.DataAdapter = da 
      da.Update(ds)

      Print(ds)

      ds.Clear() : da.Fill(ds) : Print(ds)

      Drop(cmd) 
      Console.ReadLine() 
    End Sub 
    ... 
  End Module 
End Namespace

Nach der Initialisierung der Verbindung, des Kommandos und des DataAdapters wird in der Methode Create eine Tabelle zum Testen erzeugt. Dieser Tabelle werden dann zwei neue Zeilen hinzugefügt, und die Datenbank wird mit Update aktualisiert (der Grund für den CommandBuilder wird im nächsten Abschnitt erläutert). Schließlich werden die lokale Tabelle und die erneut von der Datenbank ausgelesene Tabelle mit Print ausgegeben. In Create wird eine neue Tabelle Produkte erzeugt, die erst nach dem Einlesen und nochmaligen Abfragen bekannt ist. Vor dem endgültigen Befüllen wird die Autoinkrementierung parametrisiert (FillSchema hat bereits AutoIncrement=True gesetzt).


'...\ADO\DataSet\AutoInkrement.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module AutoInkrement 
    ... 
    Sub Print(ByVal ds As DataSet) 
      Console.WriteLine("Produkte: ") 
      For Each row As DataRow In ds.Tables(0).Rows 
        Console.WriteLine("{0,3}{1,35}", row(0), row(1)) 
      Next 
    End Sub

    Function Create(ByVal cmd As DbCommand, ByVal da As DbDataAdapter) As DataSet 
      cmd.CommandText = _ 
        "SELECT TOP 2 ProductID, ProductName INTO Produkte FROM Products" 
      Dim ds As New DataSet() 
      da.SelectCommand = cmd : da.Fill(ds)

      cmd.CommandText = "SELECT * FROM Produkte" 
      ds = New DataSet() : da.FillSchema(ds, SchemaType.Source) 
      ds.Tables(0).Columns(0).AutoIncrementSeed = –1 
      ds.Tables(0).Columns(0).AutoIncrementStep = –1 
      da.Fill(ds)

      Return ds 
    End Function

    Sub Drop(ByVal cmd As DbCommand) 
      cmd.CommandText = "DROP TABLE Produkte" 
      cmd.Connection.Open() : cmd.ExecuteNonQuery() : cmd.Connection.Close() 
    End Sub 
  End Module 
End Namespace

Die erste Ausgabe zeigt die lokalen Nummern, die zweite die endgültig von der Datenbank vergebenen:

Produkte: 
 17                       Alice Mutton 
  3                      Aniseed Syrup 
 –1                               Saft 
 –2                               Limo

Produkte: 
 18                               Saft 
 19                               Limo 
 17                       Alice Mutton 
  3                      Aniseed Syrup

Die generierten Schlüsselwerte sind nur Platzhalter innerhalb der DataTable. Erst nach der Übermittlung zur Originaldatenbank werden die endgültigen Schlüsselwerte von der Datenbank erzeugt. Sie sollten daher vermeiden, die temporären Schlüsselwerte dem Anwender anzuzeigen. Es könnte zu Missverständinssen führen, wenn der Anwender sich eine ADO.NET-Schlüsselnummer notiert, die später nach der Aktualisierung nicht mehr existiert.



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 Basic 2008
Visual Basic 2008
Jetzt Buch bestellen


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

 Buchempfehlungen
Zum Rheinwerk-Shop: Visual Basic 2012






 Visual Basic 2012


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






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


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






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


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




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