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 27 Datenbanken aktualisieren
Pfeil 27.1 Aktualisieren mit CommandBuilder
Pfeil 27.1.1 Parallelitätskonflikt
Pfeil 27.1.2 Aktualisierungsbefehle des DbCommandBuilders
Pfeil 27.1.3 Aktualisierungsoptionen des DbCommandBuilders
Pfeil 27.1.4 Vor- und Nachteile des DbCommandBuilders
Pfeil 27.2 Manuell gesteuerte Aktualisierungen
Pfeil 27.2.1 Manuelles Aktualisieren mit dem DataAdapter
Pfeil 27.2.2 Aktualisieren mit ExecuteNonQuery
Pfeil 27.3 Benutzer über fehlgeschlagene Aktualisierungen informieren
Pfeil 27.4 Konfliktverursachende Datenzeilen bei der Datenbank abfragen
Pfeil 27.5 DataSet mit der Datenbank synchronisieren
Pfeil 27.5.1 UpdatedRowSource in DbCommand
Pfeil 27.6 Hierarchische Änderungen an die Datenbank übermitteln
Pfeil 27.6.1 Datenbank auslesen
Pfeil 27.6.2 Änderung
Pfeil 27.6.3 Bestellung einfügen
Pfeil 27.6.4 Bestelldetails einfügen
Pfeil 27.6.5 Wiederherstellen der Datenbank


Rheinwerk Computing - Zum Seitenanfang

27.6 Hierarchische Änderungen an die Datenbank übermitteln Zur nächsten ÜberschriftZur vorigen Überschrift

Nicht immer haben Sie nur eine DataTable in Ihrem DataSet, die Sie aktualisieren müssen. Oft wird Ihr DataSet eine interne hierarchische Struktur mit Tabellen haben, die miteinander in Beziehung stehen. Die mit der Änderung solcher Strukturen zusammenhängenden Aspekte beschreibe ich in diesem Abschnitt.

Im Folgenden werden wir exemplarisch die beiden Tabellen Order Details und Orders der Northwind-Datenbank betrachten. Orders ist die Mastertabelle und Order Details die Detailtabelle (siehe Abbildung 27.2).

Abbildung 27.2 Beziehung der Tabellen »Orders« und »Order Details«

Nehmen wir an, der Anwender hat eine Reihe von Änderungen an den Daten vorgenommen und möchte diese nun der Datenbank übermitteln. Die referenziellen Integritätseinschränkungen erzwingen eine bestimmte Reihenfolge bei der Datenübermittlung. Wir müssen zuerst die Daten der neuen Datensätze in der Tabelle Orders in die Datenbank schreiben und können erst danach die entsprechenden neuen Datenzeilen in der Tabelle Order Details übermitteln. Zum Löschen einer Bestellung muss man genau den umgekehrten Weg gehen: Zuerst müssen alle Bestelldetails einer konkreten Bestellung in Order Details gelöscht werden, ehe die Bestellung in Orders gelöscht werden kann. Damit können im Allgemeinen anstehende Aktualisierungen nicht in einem Rutsch durchgeführt werden, sondern die Reihenfolge muss explizit kontrolliert werden.

Das folgende Codefragment zeigt die Grobstruktur des Vorgehens, die Details folgen weiter unten. Zuerst werden die beiden Tabellen ausgelesen und mit DataRelation in Beziehung zueinander gesetzt. Danach wird das DataSet geändert und die neuen Bestellungen zur späteren Löschung in Reset() gespeichert. Um die referenzielle Integrität zu wahren, werden erst die Bestellungen und dann die Details aktualisiert. Für den Abgleich der Bestellungen wird ein Ereignishandler registriert, der sich um die Autoinkrementspalte OrderID kümmert. Schließlich werden die Bestellungen protokolliert und wird die Datenbank restauriert.


'...\ADO\Aktualisierung\Beziehungen.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
 
Module Beziehungen
   
...
   
Private con As DbConnection = _
     
New SqlConnection("Data Source=(local);" & _
       
"Initial Catalog=Northwind;Integrated Security=sspi")
   
Private ds As New DataSet()
   
Private Bestellungen, Details As DataTable
   
Sub Test()

     
' Datenbank auslesen
     
Dim daDetails As DbDataAdapter = Lesen("[Order Details]")
     
Dim daOrders As DbDataAdapter = Lesen("Orders")
      Bestellungen
= ds.Tables("Orders")
      Details
= ds.Tables("[Order Details]")

     
' Datenrelation erzeugen
     
Dim rel As New DataRelation("Bez", _
          Bestellungen
.Columns("OrderID"), Details.Columns("OrderID"))
      ds
.Relations.Add(rel)

     
' neue Bestellung mit 2 Posten ProductID,UnitPrice,Quantity,Discount
     
LokaleÄnderungen(ds, New Object()() _
               
{New Object() {1, 12, 3, 0}, New Object() {2, 8.89, 3, 0}})
     
Dim Neu() As DataRow = _
        Bestellungen
.Select("", "", DataViewRowState.Added)

     
' Datenbank aktualisieren
      daOrders
.InsertCommand = InsertCommand()
     
AddHandler CType(daOrders, SqlDataAdapter).RowUpdated, _
                 
AddressOf Änderung
      daOrders
.Update(Neu) ' Zeilen
      daDetails
.InsertCommand = DetailsInsertCommand()
      daDetails
.Update(Details.GetChanges(DataRowState.Added)) ' Tabelle

     
For Each row As DataRow In Neu
        Console
.WriteLine("Bestellung mit Nummer {0}", row("OrderID"))
     
Next
     
Reset(Neu)

      Console
.ReadLine()
   
End Sub
 
End Module
End Namespace

Jeder Aufruf des Programms zeigt eine neue Bestellnummer:

Bestellung mit Nummer 11093

Zur Selektion der geänderten Zeilen verwendet das Beispiel der Vollständigkeit halber die Methoden Select und GetChanges von DataTable. Die Methode GetChanges ist auch für DataSet definiert und speichert die Änderungen in einem DataSet (statt in einer DataTable). Um alle Arten von Änderungen zu sammeln, wird sie parameterlos aufgerufen.


Rheinwerk Computing - Zum Seitenanfang

27.6.1 Datenbank auslesen Zur nächsten ÜberschriftZur vorigen Überschrift

Da die Aktualisierung der Datenbank nach Tabellen getrennt erfolgt, ist jede mit ihrem eigenen DataAdapter verbunden. Das Auslesen erfolgt analog und ist in einer Methode zusammengefasst. Sie liest nur die Metadaten mit FillSchema, da die vorhandenen Daten im Beispiel nicht gebraucht werden. Die Verknüpfung der Tabellen war bereits in Test() weiter oben zu sehen.


'...\ADO\Aktualisierung\Beziehungen.vb

Function Lesen(ByVal tabelle As String) As DbDataAdapter 
 
Dim cmd As DbCommand = New SqlCommand()
  cmd
.Connection = con : cmd.CommandText = "SELECT * FROM " & tabelle
 
Dim da As DbDataAdapter = New SqlDataAdapter()
  da
.SelectCommand = cmd
  da
.FillSchema(ds, SchemaType.Source, tabelle)
 
Return da
End Function

Rheinwerk Computing - Zum Seitenanfang

27.6.2 Änderung Zur nächsten ÜberschriftZur vorigen Überschrift

Das Beispiel fügt eine Bestellung mit den zugehörigen Details ein. Zuerst wird eine neue Bestellung mit beliebiger OrderID angelegt, die dann in den Details referenziert wird. Der Wert von OrderID spielt keine Rolle, da die Spalte automatisch von der Datenbank belegt wird (Autoinkrement). Exemplarisch für weitere Daten wird das Datum gesetzt. Um die Funktion flexibel zu halten, werden die Werte der Details als zweiter Parameter übergeben. Der Aufruf erfolgt in der oben gezeigten Methode Test().


'...\ADO\Aktualisierung\Beziehungen.vb

Sub LokaleÄnderungen(ByVal ds As DataSet, ByVal vals()() As Object) 
 
Dim Auftrag As DataRow = Bestellungen.NewRow()
  Auftrag
("OrderID") = 100 'wird in Datenbank neu vergeben
  Auftrag
("OrderDate") = DateTime.Today
 
Bestellungen.Rows.Add(Auftrag)
 
' neue [Order Details](OrderID,ProductID,UnitPrice,Quantity,Discount)
 
Dim Posten As DataRow
 
For Each row As Object() In vals
    Posten
= Details.NewRow()
    Posten
("OrderID") = Auftrag("OrderID")
   
For i As Integer = 0 To row.Length 1
      Posten
(Details.Columns(i + 1)) = row(i)
   
Next
   
Details.Rows.Add(Posten)
 
Next
End Sub

Rheinwerk Computing - Zum Seitenanfang

27.6.3 Bestellung einfügen Zur nächsten ÜberschriftZur vorigen Überschrift

Das Hinzufügen einer Bestellung besteht aus zwei Teilen:

  • Aktualisierung der Datenbank mit dem Kommando InsertCommand()
  • Bezug der von der Datenbank vergebenen OrderID im Ereignishandler Änderung()

Die Aktualisierung berücksichtigt exemplarisch das Bestelldatum:


'...\ADO\Aktualisierung\Beziehungen.vb

Function InsertCommand() As DbCommand 
 
Dim cmd As DbCommand = New SqlCommand()
  cmd
.CommandText = "INSERT INTO Orders (OrderDate) Values(@Date)"
  cmd
.Connection = con
 
Dim col As DbParameterCollection = cmd.Parameters
  col
.Add(New SqlParameter("@Date", SqlDbType.DateTime, 8, "OrderDate"))
 
Return cmd
End Function

Nach der Änderung der Datenbank liegt ein neuer Wert für OrderID vor, der in @@Identity gespeichert ist und den der Ereignishandler mit ExecuteScalar() abfragt. Die mit FillSchema() ermittelte Metainformation kennzeichnet die Primärschlüsselspalte OrderID als schreibgeschützt. In unserem Fall müssen wir diesen Schutz umgehen, um die lokalen Daten im DataSet mit den neu vergebenen Werten in der Datenbank abzugleichen. Durch die weiter oben definierte DataRelation() erhalten in der Tabelle Order Details alle korrespondierenden Werte automatisch dieselbe OrderID.


'...\ADO\Aktualisierung\Beziehungen.vb

Sub Änderung(ByVal sender As Object, ByVal ev As RowUpdatedEventArgs) 
 
If ev.Status = UpdateStatus.Continue AndAlso _
    ev
.StatementType = StatementType.Insert Then
   
Dim cmd As DbCommand = New SqlCommand()
    cmd
.CommandText = "SELECT @@Identity" : cmd.Connection = con
    Bestellungen
.Columns("OrderID").ReadOnly = False
    ev
.Row("OrderID") = cmd.ExecuteScalar() 'Verbindung bereits offen
    Bestellungen
.Columns("OrderID").ReadOnly = True
   
'[Order Details](OrderID) automatisch durch Fremdschlüsselbeziehung
 
End If
End Sub

Rheinwerk Computing - Zum Seitenanfang

27.6.4 Bestelldetails einfügen Zur nächsten ÜberschriftZur vorigen Überschrift

Die Synchronisation der Bestelldetails, die nach der korrespondierenden Bestellung erfolgen muss, weist keine Besonderheiten auf.


'...\ADO\Aktualisierung\Beziehungen.vb

Function DetailsInsertCommand() As DbCommand 
 
Dim cmd As DbCommand = New SqlCommand()
  cmd
.CommandText = "INSERT INTO [Order Details] " & _
   
"(OrderID,ProductID,UnitPrice,Quantity,Discount) " & _
   
"Values(@OID,@PID,@Preis,@Quant,@Red)"
  cmd
.Connection = con
 
' die Parameter der Parameters-Auflistung hinzufügen
 
Dim col As DbParameterCollection = cmd.Parameters
  col
.Add(New SqlParameter("@OID", SqlDbType.Int, 4, "OrderID"))
  col
.Add(New SqlParameter("@PID", SqlDbType.Int, 4, "ProductID"))
  col
.Add(New SqlParameter("@Preis", SqlDbType.Money, 8, "UnitPrice"))
  col
.Add(New SqlParameter("@Quant", SqlDbType.SmallInt, 2, "Quantity"))
  col
.Add(New SqlParameter("@Red", SqlDbType.Real, 4, "Discount"))
 
Return cmd
End Function

Rheinwerk Computing - Zum Seitenanfang

27.6.5 Wiederherstellen der Datenbank topZur vorigen Überschrift

Schließlich müssen wir noch die eingefügten Zeilen wieder aus der Datenbank entfernen. Um die referenzielle Integrität nicht zu verletzen, müssen die Details vor den zugehörigen Bestellungen gelöscht werden. Im umgekehrten Fall würden sich sonst einige Details auf eine nicht mehr vorhandene Bestellung beziehen.


'...\ADO\Aktualisierung\Beziehungen.vb

Sub Reset(ByVal Neu As IEnumerable(Of DataRow)) 
 
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
  con
.Open()
 
For Each row As DataRow In Neu
   
Dim i As Integer = CType(row("OrderID"), Integer)
    cmd
.CommandText = "DELETE [Order Details] WHERE OrderID=" & i
    cmd
.ExecuteNonQuery()
    cmd
.CommandText = "DELETE Orders WHERE OrderID=" & i
    cmd
.ExecuteNonQuery()
 
Next
  con
.Close()
End Sub



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