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