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 28 Stark typisierte DataSets
Pfeil 28.1 Erzeugung
Pfeil 28.1.1 Visual Studio Designer
Pfeil 28.1.2 Das Kommandozeilentool XSD.exe
Pfeil 28.2 Anatomie
Pfeil 28.2.1 Grobstruktur: Datentypen
Pfeil 28.2.2 Das typisierte DataSet
Pfeil 28.2.3 TableAdapter
Pfeil 28.2.4 Typisierte Tabelle
Pfeil 28.2.5 Typisierte Zeile
Pfeil 28.3 Datenzugriff
Pfeil 28.3.1 Datenzeilen ausgeben
Pfeil 28.3.2 Datenzeilen hinzufügen
Pfeil 28.3.3 Datenzeilen bearbeiten
Pfeil 28.3.4 Datenzeilen suchen
Pfeil 28.3.5 Spalten mit Null-Wert
Pfeil 28.3.6 Tabellenbeziehungen
Pfeil 28.4 Ein typisiertes DataSet manuell erzeugen
Pfeil 28.4.1 DataTable erzeugen
Pfeil 28.4.2 Spalten hinzufügen
Pfeil 28.4.3 Tabellenbeziehungen erstellen
Pfeil 28.5 TableAdapter erzeugen
Pfeil 28.5.1 Visual Studio Assistent
Pfeil 28.6 TableAdapter verwenden
Pfeil 28.6.1 Datenbeschaffung mit Fill
Pfeil 28.6.2 Datenbeschaffung mit GetData
Pfeil 28.6.3 Aktualisierung mit Update
Pfeil 28.6.4 Aktualisieren mit UpdateAll
Pfeil 28.6.5 Direkte Aktualisierung der Datenbank
Pfeil 28.6.6 TableAdapter mit mehreren Abfragen
Pfeil 28.6.7 TableAdapter ändern
Pfeil 28.7 Fazit: Typisierte oder nicht typisierte DataSets?


Rheinwerk Computing - Zum Seitenanfang

28.6 TableAdapter verwenden Zur nächsten ÜberschriftZur vorigen Überschrift

Der TableAdapter ist auf genau eine bestimmte Abfrage spezialisiert. Alle datenbankrelevanten Informationen werden im Code abgelegt, sodass es reicht, wenn Sie den Adapter mit einem parameterlosen Konstruktor instanziieren – eine Parameterübergabe oder die Festlegung von Eigenschaften sind überflüssig. Durch die Spezialisierung arbeitet der TableAdapter nur mit Tabellen zusammen, die den Typ haben, der im generierten typisierten DataSet festgelegt ist. Das typisierte DataSet und der TableAdapter bilden eine logische Einheit, trotzdem liegen beide in unterschiedlichen Namensräumen (aus meiner Sicht ein unglückliches Design).


Rheinwerk Computing - Zum Seitenanfang

28.6.1 Datenbeschaffung mit Fill Zur nächsten ÜberschriftZur vorigen Überschrift

Die Fill-Methode der Klasse SqlDataAdapter hat eine Reihe von Überladungen. Im Gegensatz dazu erwartet die Fill-Methode des TableAdapters nur die Instanz der typisierten Tabelle. In Abschnitt 28.2.3, »TableAdapter haben Sie bereits ein Beispiel gesehen. Die Eigenschaft ClearBeforeFill des TableAdapters hat den Standardwert True, sodass jeder Aufruf der Fill-Methode die Tabelle vollständig ersetzt. Damit jeder Aufruf von Fill jeweils Datenzeilen anhängt, setzen Sie den Parameter auf False.


Rheinwerk Computing - Zum Seitenanfang

28.6.2 Datenbeschaffung mit GetData Zur nächsten ÜberschriftZur vorigen Überschrift

Ähnlich wie Fill arbeitet auch die Methode GetData. Allerdings müssen Sie sich vorher keine Instanz des typisierten DataSets besorgen. Der Code wird etwas kürzer.


'...\ADO\DataSetTypisiert\GetData.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module GetData 
    Sub Test() 
      Dim nw As New NWTableAdapterTableAdapters.ProductsTableAdapter() 
      Dim tab As NWTableAdapter.ProductsDataTable = nw.GetData() 
      Dim tab2 As NWTableAdapter.ProductsDataTable = nw.GetData() 
      Console.WriteLine("ProduktID {0}", tab(0).ProductID) 
      Console.WriteLine("ProduktID {0}", tab2(0).ProductID) 
      Console.WriteLine("Dieselben Tabellen: {0}", tab Is tab2) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Wichtig ist, dass jeder Aufruf von GetData eine neue Tabelle erzeugt, wie die letzte Zeile der Ausgabe zeigt:

ProduktID 1 
ProduktID 1 
Dieselben Tabellen: False

Rheinwerk Computing - Zum Seitenanfang

28.6.3 Aktualisierung mit Update Zur nächsten ÜberschriftZur vorigen Überschrift

Die Methode Update des TableAdapters synchronisiert die lokalen Daten im übergebenen typisierten DataSet mit der Datenbank. Alternativ kann auch eine DataTable oder eine einzelne Zeile oder ein Array von DataRow abgeglichen werden. Im folgenden Codefragment werden eine neue Kategorie Wein und ein dazugehöriges Produkt Bordeaux dem DataSet hinzugefügt. Danach wird die Categories-Tabelle im DataSet mit der Datenbank abgeglichen. Damit im Fehlerfall die Aktion rückgängig gemacht werden kann, wird die für das Update- Kommando benötigte Einfügeoperation innerhalb einer Transaktion ausgeführt. Dazu wird die Verbindung zur Datenbank geöffnet, eine Transaktion gestartet und für Insert verwendet. Erst danach wird Update aufgerufen. Im zweiten Teil des Abgleichs wird die Products-Tabelle der Datenbank aktualisiert und die Transaktion der Categories-Tabelle mit einem Commit abgeschlossen. Im Fehlerfall ist der Abgleich der Products-Tabelle gescheitert, und die erste Einfügeoperation wird mit Rollback rückgängig gemacht.


'...\ADO\DataSetTypisiert\Transaktion.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module Transaktion 
    Sub Test() 
      Dim nw As New NWDataSet() 
      Dim nwc As New NWDataSetTableAdapters.CategoriesTableAdapter() 
      Dim nwp As New NWDataSetTableAdapters.ProductsTableAdapter() 
      nwc.Fill(nw.Categories) 
      nwp.Fill(nw.Products) 
      Dim row As NWDataSet.CategoriesRow = _ 
        nw.Categories.AddCategoriesRow("Wein") 
      nw.Products.AddProductsRow("Bordeaux", row, 12D)

      nwc.Connection.Open() 
      Dim tr As SqlTransaction = nwc.Connection.BeginTransaction() 
      nwc.Adapter.InsertCommand.Transaction = tr 
      nwc.Update(nw) 
      Try 
        nwp.Update(nw) 
        tr.Commit() 
      Catch ex As Exception 
        Console.WriteLine("Fehler: {0}", ex.Message) 
        tr.Rollback() 
      End Try 
      nwc.Connection.Close()

      nwc.Fill(nw.Categories) 
      Console.WriteLine("Art: {0}", _ 
        nw.Categories(nw.Categories.Rows.Count – 1).CategoryName) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Ausgabe zeigt, dass etwas schiefgegangen ist, und die letzte Zeile der Categories-Tabelle wurde mit Rollback in den Ursprungszustand versetzt.

Fehler: Die INSERT-Anweisung steht in Konflikt mit der FOREIGN KEY-Einschränkung 
 "FK_Products_Categories". Der Konflikt trat in der "Northwind"-Datenbank, 
Tabelle "dbo.Categories", column 'CategoryID' auf. 
Die Anweisung wurde beendet. 
Art: Seafood

Die Spalte CategoryID der Categories-Tabelle ist ein Autoinkrementwert. Der im lokalen DataSet verwendete Wert hat keinen Bezug zu dem Wert, der von der Datenbank vergeben wird. Damit hat die Zeile in der Methode AddProductsRow() eine CategoryID, die gegebenenfalls in der Datenbank gar nicht existiert. Dies ist aber aufgrund der Fremdschlüsseleinschränkung der Products-Tabelle nicht erlaubt. Die Lösung besteht darin, den neuen Wert von der Datenbank abzuholen und als Referenz zu verwenden. Für den in Abschnitt 28.5.1, »Visual StudioAssistent« erstellten TableAdapter wurde, wie in Abbildung 28.11, »Erweiterte Optionen des TableAdapter-Konfigurationsassistenten«, gezeigt, mit der dritten Option dies automatisch gewährleistet. Für das hier verwendete und in Abschnitt 28.1.1, »Visual Studio Designer«, erzeugte DataSet erfolgt dies im nächsten Codefragment manuell. Dazu wird mit Update die Categories-Tabelle der Datenbank aktualisiert und werden mit Fill die neuen Daten in das DataSet übernommen. Um das Beispiel allgemein zu halten, wird nicht angenommen, dass die neue Zeile als letzte eingefügt wurde, sondern sie wird mit einem LINQ-Ausdruck herausgesucht. Diese aktualisierte Zeile kann nun problemlos in AddProductsRow verwendet werden.


'...\ADO\DataSetTypisiert\Update.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module Update 
    Sub Test() 
      Dim nw As New NWDataSet() 
      Dim nwc As New NWDataSetTableAdapters.CategoriesTableAdapter() 
      Dim nwp As New NWDataSetTableAdapters.ProductsTableAdapter() 
      nwc.Fill(nw.Categories) 
      nwp.Fill(nw.Products)

      Dim row As NWDataSet.CategoriesRow = _ 
        nw.Categories.AddCategoriesRow("Wein") 
      nwc.Update(nw) 
      nwc.Fill(nw.Categories) 
      row = (From cat As NWDataSet.CategoriesRow In nw.Categories _ 
             Where cat.CategoryName = "Wein").First()

      nw.Products.AddProductsRow("Bordeaux", row, 12D) 
      nwp.Update(nw)

      Console.WriteLine("Art: {0}", _ 
        nw.Categories(nw.Categories.Rows.Count – 1).CategoryName) 
      Console.WriteLine("Produkt: {0}", _ 
        nw.Products(nw.Products.Rows.Count – 1).ProductName) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Nun ist die Änderung auch in der Datenbank angekommen.

Art: Wein 
Produkt: Bordeaux

Das TableAdapter-Objekt hat eine Methode Update, um Änderungen an die Datenbank zu übermitteln. Die Methode akzeptiert ein typisiertes DataSet oder eine typisierte DataTable als Argument, ebenso auch eine einzelne DataRow oder ein Array von DataRows. Damit unterscheidet sich die Update-Methode des TableAdapters nur unwesentlich von der Update-Methode des SqlDataAdapters.


Rheinwerk Computing - Zum Seitenanfang

28.6.4 Aktualisieren mit UpdateAll Zur nächsten ÜberschriftZur vorigen Überschrift

Sollten Sie mehrere Insert-, Update- und Delete-Anweisungen zum Datenbankabgleich benötigen, bietet der TableAdapterManager eine Methode UpdateAll, die sich automatisch um die richtige Reihenfolge der Befehle kümmert. Im folgenden Beispiel werden die im letzten Abschnitt hinzugefügten Zeilen mit einem LINQ-Ausdruck ermittelt und aus dem DataSet gelöscht. Bevor die Methode UpdateAll() des TableAdapterManagers den Datenbankabgleich vornehmen kann, muss dieser noch über die zu verwendenden TableAdapter informiert werden. Die Methode kümmert sich automatisch darum, erst die Detailtabelle Products und dann erst die Mastertabelle Categories zu bearbeiten.


'...\ADO\DataSetTypisiert\UpdateAll.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module UpdateAll 
    Sub Test() 
      Dim nw As New NWDataSet() 
      Dim nwc As New NWDataSetTableAdapters.CategoriesTableAdapter() 
      Dim nwp As New NWDataSetTableAdapters.ProductsTableAdapter() 
      nwc.Fill(nw.Categories) 
      nwp.Fill(nw.Products)

      Dim cats = From cat As NWDataSet.CategoriesRow In nw.Categories _ 
                 Where cat.CategoryName = "Wein" 
      Dim prods = From prod As NWDataSet.ProductsRow In nw.Products _ 
                  Where prod.CategoryID = cats.First().CategoryID 
      prods.First().Delete() 
      cats.First().Delete()

      Dim nwa As New NWDataSetTableAdapters.TableAdapterManager() 
      nwa.ProductsTableAdapter = nwp 
      nwa.CategoriesTableAdapter = nwc 
      nwa.UpdateAll(nw)

      nwc.Fill(nw.Categories) 
      nwp.Fill(nw.Products) 
      Console.WriteLine("Art: {0}", _ 
        nw.Categories(nw.Categories.Rows.Count – 1).CategoryName) 
      Console.WriteLine("Produkt: {0}", _ 
        nw.Products(nw.Products.Rows.Count – 1).ProductName) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Die Datenbank hat die Änderungen übernommen, und die Änderungen des letzten Abschnitts wurden rückgängig gemacht:

Art: Seafood 
Produkt: Original Frankfurter grüne Soße

Rheinwerk Computing - Zum Seitenanfang

28.6.5 Direkte Aktualisierung der Datenbank Zur nächsten ÜberschriftZur vorigen Überschrift

Die Datenbank kann auch direkt ohne lokale Speicherung in einem DataSet geändert werden. In der folgenden Syntax sind optionale Teile in eckige Klammern gesetzt. Alle Funktionen liefern als Ergebnis die Anzahl der betroffenen Zeilen in der Datenbank.


Insert(<Neue Werte ohne Autoinkrement>) 
Update(<Neue Werte ohne Autoinkrement>, <Datenbankwerte>, 
  [<Temporäre Autoinkrementwerte>]) 
Delete(<Datenbankwerte>)

Die kursiv gesetzten Namen sind für jedes typisierte DataSet entsprechend konkretisiert. Hier also ergeben sich aufgrund der Abfrage

SELECT ProductID, ProductName, CategoryID, UnitPrice FROM Products

des typisierten DataSets die folgenden Methoden:

Insert(ProductName, CategoryID, UnitPrice) 
Update(ProductName, CategoryID, UnitPrice, _ 
  OrigProductID, OrigProductName, OrigCategoryID, OrigUnitPrice _ 
  [, ProductID]) As Integer 
Delete(OrigProductID, OrigProductName, OrigCategoryID, OrigUnitPrice)

Das folgende Codefragment zeigt die drei Funktionen in Aktion. Beim Einfügen der neuen Zeilen wird der Spalte ProductID von der Datenbank automatisch ein Wert zugewiesen. Um diesen bei den Update- und Delete-Kommandos zur Verfügung zu haben, wird die Datenbank abgefragt und werden die neuen Werte in p und s abgelegt.


'...\ADO\DataSetTypisiert\Direkt.vb

Option Strict On 
Imports System.Data.Common, System.Data.SqlClient 
Namespace ADO 
  Module Direkt 
    Sub Test() 
      Dim nw As New NWTableAdapter() 
      Dim ta As New NWTableAdapterTableAdapters.ProductsTableAdapter()

      ta.Insert("Printen", 2D) 
      ta.Insert("Marzipan", 2D)

      ta.Fill(nw.Products) 
      Dim p = (From prod As NWTableAdapter.ProductsRow In nw.Products _ 
               Where prod.ProductName = "Printen").First().ProductID 
      Dim s = (From prod As NWTableAdapter.ProductsRow In nw.Products _ 
               Where prod.ProductName = "Marzipan").First().ProductID

      ta.Update("Öcher Prente", 3D, p, "Printen", 2D, p) 
      ta.Update("Stippefötche", 4D, s, "Marzipan", 2D, s) 
      ta.Delete(s, "Stippefötche", 4D)

      ta.Fill(nw.Products) 
      For Each r As NWTableAdapter.ProductsRow In _ 
        nw.Products.Skip(nw.Products.Rows.Count – 2) 
        Console.WriteLine("Produkt: {0}", r.ProductName) 
      Next

      ta.Delete(p, "Öcher Prente", 3D) 'Originalzustand herstellen 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Von den beiden eingefügten Zeilen ist eine vor der Ausgabe der beiden letzten Tabellenzeilen bereits gelöscht worden.

Produkt: Original Frankfurter grüne Soße 
Produkt: Öcher Prente

Hinweis
Wird eine Zeile aufgrund falscher Werte nicht in der Datenbank gefunden, wird das entsprechende Kommando ignoriert. Es wird keine Ausnahme ausgelöst. Den Erfolg prüfen Sie mit dem Rückgabewert der Änderungsmethoden (Anzahl betroffener Zeilen).



Rheinwerk Computing - Zum Seitenanfang

28.6.6 TableAdapter mit mehreren Abfragen Zur nächsten ÜberschriftZur vorigen Überschrift

Zusätzlich zur eigentlichen Abfrage eines TableAdapters können noch Funktionen generiert werden, die Sichten auf diese Daten definieren und damit eine Auswahl der gesamten Daten zur Verfügung stellen. Eine Erweiterung der Daten ist nicht möglich. Als Beispiel zeige ich, wie Sie aus der Products-Tabelle nur Produkte einer bestimmten Kategorie auswählen. Öffnen Sie dazu im Visual Studio den Designer des typisierten DataSets, und markieren Sie den TableAdapter, der die Tabelle Products beschreibt. Einen Assistenten starten Sie über den Menüpunkt Abfrage hinzufügen des Kontextmenüs des Adapters. Im ersten Dialog entscheiden Sie sich, eine SQL-Anweisung zu verwenden, eine gespeicherte Prozedur zu erstellen oder eine vorhandene gespeicherte Prozedur zu verwenden.

Wir wählen die erste Option und geben im nächsten Schritt den Abfragetyp an. Damit wir Zeilen derselben Kategorie erhalten, entscheiden wir uns mit der obersten Option für eine normale SELECT-Abfrage (siehe Abbildung 28.14).

Abbildung 28.14 Festlegen des Abfragetyps

Bestätigen Sie mit Weiter, wird die Basisabfrage des TableAdapters angezeigt. Diese können Sie erweitern. Tragen Sie also

WHERE CategoryID = @CategoryID

in das Fenster ein, oder benutzen Sie den Abfrage-Generator (siehe Abbildung 28.15).

Abbildung 28.15 Ergänzung der Basisabfrage des TableAdapters

Im folgenden Dialog (siehe Abbildung 28.16) werden FillBy und GetDataBy als Namen für Fill und GetData der Sicht auf die Daten vorgeschlagen, die wir in die sprechenden Namen FillByCategoryID und GetDataByCategoryID abändern. Wir schließen die Codegenerierung ab, indem wir auf den Button Fertig stellen klicken.

Abbildung 28.16 Methoden »Fill« und »GetData« benennen

Das Ergebnis sehen Sie anschließend im Designer. Es liegen jetzt zwei parametrisierte Abfragen vor, denen wir CategoryID als Argument übergeben müssen (siehe Abbildung 28.17).

Abbildung 28.17 TableAdapter mit einer hinzugefügten Abfrage

Testen wir zuerst die Methode FillByCategoryID. Hierzu benötigen wir je eine Instanz des typisierten DataSets sowie des TableAdapters, um die Methode FillByCategoryID des TableAdapter-Objekts aufzurufen. Neben der zu füllenden Tabelle wird der Methode als zweiter Parameter die Kategorie übergeben, die wir heraussuchen wollen.

Dim nw As New NWDataSet() 
Dim nwa As New NWDataSetTableAdapters.ProductsTableAdapter() 
nwa.FillByCategoryID(nw.Products, 5) 
For Each zeile As NWDataSet.ProductsRow In nw.Products 
  Console.WriteLine("Produkt {0} in Kategorie {1} ", _ 
    zeile.ProductName, zeile.CategoryID) 
Next

Die Methode GetData erfordert etwas weniger Code, und die Instanz des typisierten DataSets wird nicht benötigt. Auch diese Methode erwartet die Kategorienummer.

Dim nwa As New NWDataSetTableAdapters.ProductsTableAdapter() 
Dim p As NWDataSet.ProductsDataTable = nwa.GetDataByCategoryID(5) 
For Each zeile As NWDataSet.ProductsRow In p 
  Console.WriteLine("Produkt {0} in Kategorie {1} ", _ 
    zeile.ProductName, zeile.CategoryID) 
Next

Rheinwerk Computing - Zum Seitenanfang

28.6.7 TableAdapter ändern topZur vorigen Überschrift

Wenn Sie den TableAdapter im Designer markieren, werden dessen Eigenschaften im Eigenschaftsfenster von Visual Studio angezeigt (siehe Abbildung 28.18). Sie können hier nicht nur die Verbindungsinformationen neu festlegen, sondern auch die SELECT-Abfrage. Ergänzen Sie diese beispielsweise um eine Spalte, werden die Aktualisierungsabfragen UPDATE, INSERT und DELETE nach vorheriger Bestätigung der Änderung angepasst.

Besonders interessant sind die Manipulationsmöglichkeiten, die sich hinter den Eigenschaften DeleteCommand und UpdateCommand verbergen. Da Sie dort die WHERE-Klausel festlegen können, haben Sie hier Einfluss auf das Verhalten im Konfliktfall.

Abbildung 28.18 Das Eigenschaftsfenster eines TableAdapters



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