Galileo Computing < openbook > Galileo 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

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 32 ADO.NET – Das Command-Objekt
Pfeil 32.1 Die Datenbankabfrage
Pfeil 32.2 Das SqlCommand-Objekt
Pfeil 32.2.1 Erzeugen eines SqlCommand-Objekts
Pfeil 32.2.2 Die Methode »CreateCommand« des Connection-Objekts
Pfeil 32.2.3 Ausführen des SqlCommand-Objekts
Pfeil 32.2.4 Die Eigenschaft »CommandTimeout« des SqlCommand-Objekts
Pfeil 32.3 Aktionsabfragen absetzen
Pfeil 32.3.1 Datensätze hinzufügen
Pfeil 32.3.2 Datensätze löschen
Pfeil 32.3.3 Datensätze ändern
Pfeil 32.3.4 Abfragen, die genau ein Ergebnis liefern
Pfeil 32.4 Das SqlDataReader-Objekt
Pfeil 32.4.1 Datensätze einlesen
Pfeil 32.4.2 Schließen des SqlDataReader-Objekts
Pfeil 32.4.3 MARS (Multiple Active Resultsets)
Pfeil 32.4.4 Batchabfragen mit »NextResult« durchlaufen
Pfeil 32.4.5 Das Schema eines SqlDataReader-Objekts untersuchen
Pfeil 32.5 Parametrisierte Abfragen
Pfeil 32.5.1 Parametrisierte Abfragen mit dem SqlClient-Datenprovider
Pfeil 32.5.2 Die Klasse »SqlParameter«
Pfeil 32.5.3 Asynchrone Abfragen
Pfeil 32.5.4 Gespeicherte Prozeduren (Stored Procedures)

Galileo Computing - Zum Seitenanfang

32.4 Das SqlDataReader-ObjektZur nächsten Überschrift

Mit der Methode ExecuteNonQuery des SqlCommand-Objekts können Sie Datensätze in der Originaldatenbank manipulieren und mit ExecuteScalar ein einzelnes Abfrageergebnis abrufen. Möchte man sich die Datensätze einer Tabelle in einer Anwendung anzeigen lassen, wird die Methode ExecuteReader des SqlCommand-Objekts aufgerufen.

Der Rückgabewert des Methodenaufrufs ist ein Objekt vom Typ SqlDataReader. Dieses ähnelt den anderen Reader-Objekten des .NET Frameworks (TextReader, StreamReader usw.). Ein SqlDataReader-Objekt liest aus einer Ergebnisliste, die schreibgeschützt ist und sich in einem serverseitigen Puffer befindet, also auf der Seite der Datenbank. Sie sollten daher beherzigen, die Ergebnisliste so schnell wie möglich abzurufen, damit die beanspruchten Ressourcen wieder freigegeben werden.

In einer von einem SqlDataReader-Objekt bereitgestellten Datensatzliste kann immer nur zum folgenden Datensatz navigiert werden. Eine beliebige Navigation in der Ergebnisliste ist nicht möglich und ebenso wenig das Ändern der gelieferten Daten. Damit hat ein SqlDataReader nur eine sehr eingeschränkte Funktionalität. Dieses Manko wird andererseits durch die sehr gute Performance wettgemacht – das ist die Stärke des SqlDataReaders.

Das Erzeugen eines DataReader-Objekts funktioniert nur über den Aufruf der Methode ExecuteReader auf die SqlCommand-Referenz, denn die Klasse SqlDataReader weist keinen öffentlichen Konstruktor auf.

SqlDataReader reader = cmd.ExecuteReader();

Galileo Computing - Zum Seitenanfang

32.4.1 Datensätze einlesenZur nächsten ÜberschriftZur vorigen Überschrift

Im folgenden Beispielprogramm wird ein SqlDataReader dazu benutzt, alle Artikel zusammen mit ihrem Preis nach dem Preis sortiert auszugeben.

// Beispiel: ..\Kapitel 32\DataReaderSample

static void Main(string[] args) {
SqlConnection con = new SqlConnection("...");
string strSQL = "SELECT ProductName, Unitprice " +
"FROM Products " +
"ORDER BY[UnitPrice]";
SqlCommand cmd = new SqlCommand(strSQL, con);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
Console.WriteLine("{0,-35}{1}",
reader["ProductName"], reader["UnitPrice"]);
reader.Close();
con.Close();
}

Listing 32.6 Daten abrufen mit »ExecuteReader«

Zuerst wird die Zeichenfolge des SELECT-Statements definiert, die im nächsten Schritt zusammen mit der Referenz auf das SqlConnection-Objekt dazu dient, ein SqlCommand-Objekt zu erzeugen. Auf das SqlCommand-Objekt wird nach dem Öffnen der Verbindung die Methode ExecuteReader ausgeführt. Der Rückgabewert wird in der Objektvariablen reader vom Typ SqlDataReader gespeichert.

SqlDataReader liefert alle Datensätze, die der Reihe nach durchlaufen werden müssen. Um auf die Datensätze zuzugreifen, gibt es nur eine Möglichkeit: die Methode Read des DataReader-Objekts. Jeder Aufruf von Read legt die Position des SqlDataReaders neu fest. Die Ausgangsposition vor dem ersten Read-Aufruf ist vor dem ersten Datensatz. Nach dem Aufruf von Read ist der Rückgabewert true, falls noch eine weitere Datenzeile abgerufen werden kann. Ist der Rückgabewert false, ist kein weiterer Datensatz mehr verfügbar. Damit eignet sich Read, um die Datensatzliste in einer while-Schleife zu durchlaufen.

Beabsichtigen Sie, wiederholt die Datensätze im SqlDataReader auszuwerten, müssen Sie die Methode ExecuteReader erneut aufrufen.

Auswerten der einzelnen Spalten in DataReader

Mit Read wird die Position des SqlDataReaders auf die folgende Datenzeile verschoben. In unserem Beispiel hat jede Datenzeile zwei Feldinformationen, nämlich die der Spalten ProductName und UnitPrice. Die einzelnen Spalten einer Abfrage werden in einer Auflistung geführt, auf die über den Index des SqlDataReader-Objekts zugegriffen werden kann:

reader[0]

Sie können auch den Spaltenbezeichner angeben, also:

reader["ProductName"]

Diese Angaben sind gleichwertig. Bezüglich der Performance gibt es jedoch einen Unterschied. Geben Sie den Spaltennamen an, muss das SqlDataReader-Objekt zuerst die Spalte in der Auflistung suchen – und das bei jeder Datenzeile.

while (reader.Read())
Console.WriteLine("{0,-35}{1}", reader["ProductName"], reader["UnitPrice"]);

Um die Leistung Ihrer Anwendung zu steigern, sollten Sie daher den Index der betreffenden Spalte angeben:

while(reader.Read())
Console.WriteLine("{0,-35}{1}",reader[0], reader[1]);

Ist Ihnen nur der Spaltenbezeichner, jedoch nicht der dazugehörige Index bekannt, haben Sie mit der Methode GetOrdinal der Klasse DataReader unter Angabe des Spaltenbezeichners die Möglichkeit, vor dem Aufruf von Read den Index zu ermitteln:

int intName = reader.GetOrdinal("ProductName");
int intPrice = reader.GetOrdinal("UnitPrice");
while(reader.Read())
Console.WriteLine("{0,-20}{1,-20}{2,-20}", reader[intName], reader[intPrice]);

Listing 32.7 Die Indizes der Spalten mit »GetOrdinal« abrufen

Spalten mit den typspezifischen Methoden abrufen

Mit dem Indexer der Methode ExecuteReader werden die Spaltenwerte vom Typ Object zurückgegeben. Das hat Leistungseinbußen zur Folge, weil der tatsächliche Typ erst in Object umgewandelt werden muss. Anstatt über den Indexer die Daten auszuwerten, können Sie auch eine der vielen GetXxx-Methoden anwenden, die für die wichtigsten .NET-Datentypen bereitgestellt werden, beispielsweise GetString, GetInt32 oder GetBoolean. Sie müssen nur die passende Methode aus einer (langen) Liste auswählen und beim Aufruf die Ordinalzahl der entsprechenden Spalte übergeben. Wählen Sie eine nicht typgerechte Methode aus, kommt es zur Ausnahme InvalidCastException.

SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read()) {
Console.WriteLine(reader.GetString(0));
Console.WriteLine(reader.GetString(1));
}

Listing 32.8 Beste Performance beim Datenabruf

Auch wenn der Programmieraufwand größer ist, zur Laufzeit werden Sie dafür mit einem besseren Leistungsverhalten belohnt.

NULL-Werte behandeln

Spalten einer Tabelle können, soweit zugelassen, NULL-Werte enthalten. In der Tabelle Products betrifft das zum Beispiel die Spalte UnitPrice. Rufen Sie die Datenwerte über eine der typisierten Methoden ab und ist der Spaltenwert NULL, führt das zu einer Ausnahme.

Um diesem Problem zu begegnen, können Sie mit der Methode IsDBNull des SqlDataReaders prüfen, ob die entsprechende Spalte einen gültigen Wert oder NULL enthält.

SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read()) {
Console.WriteLine(reader.GetString(0));
if(! reader.IsDBNull(1))
Console.WriteLine(reader.GetString(1));
}

Listing 32.9 NULL-Inhalte behandeln


Galileo Computing - Zum Seitenanfang

32.4.2 Schließen des SqlDataReader-ObjektsZur nächsten ÜberschriftZur vorigen Überschrift

Der SqlDataReader blockiert standardmäßig das SqlConnection-Objekt. Solange SqlDataReader durch den Aufruf von ExecuteReader geöffnet ist, können keine anderen Aktionen auf Basis der Verbindung durchgeführt werden, auch nicht das Öffnen eines zweiten SqlDataReader-Objekts. Daher sollte die Sperre so schnell wie möglich mit

reader.Close();

aufgehoben werden.


Galileo Computing - Zum Seitenanfang

32.4.3 MARS (Multiple Active Resultsets)Zur nächsten ÜberschriftZur vorigen Überschrift

Der SQL Server hat ein Feature, das es gestattet, mehrere Anforderungen auf einer Verbindung auszuführen. Damit wird eine Verbindung nicht mehr blockiert, wenn diese einem geöffneten SqlDataReader zugeordnet ist. Diese Technik von SQL Server wird als Multiple Active Resultsets, kurz MARS bezeichnet. MARS ist per Vorgabe deaktiviert und muss zuvor aktiviert werden, um es zu nutzen. Sie aktivieren MARS entweder durch Ergänzen der Verbindungszeichenfolge um

MultipleActiveResultSets=True;

oder durch Setzen der gleichnamigen Eigenschaft im SqlConnectionStringBuilder.

MARS bietet sich an, wenn auf Basis der Ergebnismenge eines SqlDataReaders eine untergeordnete Tabellenabfrage gestartet werden soll. Das folgende Beispiel demonstriert dies. Dazu soll zu jedem Artikel auch der dazugehörige Lieferant ausgegeben werden. Damit stehen die beiden Tabellen Products und Suppliers im Mittelpunkt unserer Betrachtung, die miteinander in einer 1:n-Beziehung stehen.

Für jede Tabelle werden ein SqlCommand-Objekt sowie ein SqlDataReader-Objekt benötigt. Das erste DataReader-Objekt durchläuft die Artikeltabelle. Mit der in der Spalte SupplierID enthaltenen ID des Lieferanten wird eine untergeordnete Ergebnisliste, die der Tabelle Suppliers, durchlaufen. Hier wird die ID des Lieferanten gesucht und dessen Firmenbezeichnung zusätzlich zum Artikel ausgegeben.

// Beispiel: ..\Kapitel 32\MarsSample

static void Main(string[] args) {
SqlConnection con = new SqlConnection(
" ...;MultipleActiveResultSets=true");
string textProducts = "SELECT ProductName, UnitsInStock, SupplierID " +
"FROM Products";
string textSupplier = "SELECT CompanyName FROM Suppliers " +
"WHERE SupplierID=@SupplierID";

// SqlCommand-Objekte erzeugen

SqlCommand cmdProducts, cmdSupplier;
cmdProducts = new SqlCommand(textProducts, con);
cmdSupplier = new SqlCommand(textSupplier, con);
SqlParameter param = cmdSupplier.Parameters.Add("@SupplierID", SqlDbType.Int);

// Verbindung öffnen

con.Open();
SqlDataReader readerProducts = cmdProducts.ExecuteReader();

// Einlesen und Ausgabe der Datenzeilen an der Konsole

while (readerProducts.Read()) {
Console.Write("{0,-35}{1,-6}",
readerProducts["ProductName"], readerProducts["UnitsInStock"]);
param.Value = readerProducts["SupplierID"];
SqlDataReader readerSupplier = cmdSupplier.ExecuteReader();
while (readerSupplier.Read()) {
Console.WriteLine(readerSupplier["Companyname"]);
}
readerSupplier.Close();
Console.WriteLine(new string('-', 80));
}
readerProducts.Close();
con.Close();
}

Listing 32.10 Multiple Active Resultsets (MARS)

Der Vorteil von MARS wird in diesem Beispiel deutlich: Es genügt eine Verbindung, um mit den beiden SqlDataReader-Objekten zu operieren. Selbstverständlich kann die dem Programmcode zugrunde liegende Forderung auch ohne die Nutzung von MARS erfüllt werden. Allerdings wären dazu zwei Verbindungen notwendig, die einen gewissen Overhead verursachen.

Ein SQL-Statement kann eine parametrisierte Abfrage beschreiben. SqlCommand-Objekte unterstützen parametrisierte Abfragen durch eine Parameterliste. Weiter unten werden wir uns den parametrisierten Abfragen im Detail widmen.


Galileo Computing - Zum Seitenanfang

32.4.4 Batchabfragen mit »NextResult« durchlaufenZur nächsten ÜberschriftZur vorigen Überschrift

Müssen Sie mehrere Abfragen hintereinander absetzen, können Sie eine Batchabfrage ausführen. Allerdings werden Batchabfragen nicht von allen Datenbanken unterstützt – der SQL Server gehört aber dazu.

Nehmen wir an, Sie benötigen alle Datensätze sowohl der Tabelle Orders als auch der Tabelle Customers. Um eine syntaktisch korrekte Batchabfrage zu formulieren, werden die beiden SELECT-Statements innerhalb einer Zeichenfolge durch ein Semikolon getrennt angegeben:

SELECT * FROM Orders;SELECT * FROM Customers

Der Vorteil einer Batchabfrage ist, dass Sie die Methode ExecuteReader nicht zweimal aufrufen und nach dem ersten Aufruf den SqlDataReader schließen müssen. Selbstverständlich sind Batchabfragen nicht nur auf zwei SELECT-Anweisungen beschränkt, es können beliebig viele festlegt werden.

Das von einer Batchabfrage gefüllte SqlDataReader-Objekt enthält nach dem Aufruf der ExecuteReader-Methode mehrere Ergebnislisten. Um zwischen diesen zu wechseln, verwendet man die Methode NextResult. Die Funktionsweise ähnelt der von Read. Sie liefert true, wenn eine Datensatzliste durchlaufen wurde und sich noch eine weitere im DataReader befindet.

do {
while(dr.Read())
Console.WriteLine("{0}{1}{2}", dr[0], dr[1], dr[2]);
Console.WriteLine();
} while(dr.NextResult());

Die Überprüfung mit NextResult muss in jedem Fall im Schleifenfuß erfolgen. Eine Prüfung im Schleifenkopf hätte zur Folge, dass die erste Datensatzliste überhaupt nicht durchlaufen wird.

Gemischte Batchabfragen

Manchmal ist es erforderlich, eine Batchabfrage zu definieren, die sich aus einer oder mehreren Auswahl- und Aktionsabfragen zusammensetzt. Vielleicht möchten Sie eine SELECT-, eine DELETE- und eine UPDATE-Abfrage in einer Batchabfrage behandeln? Kein Problem. Erstellen Sie eine solche Abfrage genauso wie jede andere, also beispielsweise mit:

SELECT * FROM Products;
UPDATE Products SET ProductName='Senfsauce' WHERE ProductName='Chai'

In dieser Weise gemischte Abfragen rufen Sie ebenfalls mit der Methode ExecuteReader auf.


Galileo Computing - Zum Seitenanfang

32.4.5 Das Schema eines SqlDataReader-Objekts untersuchenZur nächsten ÜberschriftZur vorigen Überschrift

Haupteinsatz des SqlDataReader-Objekts ist sicherlich die Abfrage von Daten. Darüber hinaus weist dieser Typ aber auch weitere Fähigkeiten auf. Im Einzelnen handelt es sich dabei um die folgenden:

  • Abrufen der Schemadaten der Spalten mit der Methode GetSchemaTable. Die gelieferten Informationen beschreiben unter anderem, ob eine Spalte Primärschlüsselspalte ist, ob sie schreibgeschützt ist, ob der Spaltenwert innerhalb der Tabelle eindeutig ist oder ob die Spalte einen NULL-Wert zulässt.
  • Es lässt sich der Name einer bestimmten Spalte mit der Methode GetName ermitteln.
  • Die Ordinalposition einer Spalte lässt sich anhand des Spaltenbezeichners ermitteln. Die Methode GetOrdinal liefert den entsprechenden Index.

Die Methode »GetSchemaTable«

Der Rückgabetyp der Methode GetSchemaTable ist ein Objekt vom Typ DataTable. An dieser Stelle wollen wir diesen Typ nicht weiter betrachten. Es genügt am Anfang, zu wissen, dass sich ein DataTable-Objekt aus Datenzeilen und Spalten zusammensetzt, ähnlich einer Excel-Tabelle.

Dieser Tabelle liegt ein SELECT-Statement zugrunde, das mit ExecuteReader gegen die Datenbank ausgeführt wird. ExecuteReader haben wir bisher nur parameterlos kennengelernt; es akzeptiert aber auch einen Übergabeparameter vom Typ der Enumeration CommandBehavior. Der Member CommandBehavior.SchemaOnly gibt vor, dass die Abfrage nur Spalteninformationen zurückliefert.

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly);

Auf die SqlDataReader-Referenz kann man anschließend die Methode GetSchemaTable aufrufen. Das ist vorteilhaft, denn die übermittelten Metadaten werden nun für alle Spalten, die im SELECT-Statement angegeben sind, in der Tabelle eingetragen. Dabei wird für jede im SELECT-Statement angegebene Spalte der Originaltabelle eine Datenzeile geschrieben.

DataTable table = reader.GetSchemaTable();

Die Spalten in der Schematabelle werden durch festgelegte Bezeichner in einer bestimmten Reihenfolge ausgegeben. Die erste Spalte ist immer ColumnName, die zweite ColumnOrdinal, die dritte ColumnSize. Insgesamt werden 28 Spalten zur Auswertung bereitgestellt. Falls Sie nähere Informationen benötigen, sehen Sie sich in der .NET-Dokumentation die Hilfe zur Methode GetSchemaTable an. Das folgende Beispiel untersucht die Spalten ProductID, ProductName und UnitsInStock der Tabelle Products. Es soll dabei genügen, nur die ersten vier Metadateninformationen zu ermitteln.

// Beispiel: ..\Kapitel 32\GetSchemaTableSample

static void Main(string[] args) {
SqlConnection con = new SqlConnection("...");
string strSQL = "SELECT ProductID, ProductName, " +
"UnitsInStock FROM Products";
SqlCommand cmd = new SqlCommand(strSQL, con);
con.Open();

// Schemainformationen einlesen

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly);

// Schematabelle erstellen

DataTable table = reader.GetSchemaTable();

// Ausgabe der Schematabelle

for(int col = 0; col < 4; col++)
Console.Write("{0,-15}", table.Columns[col].ColumnName);
Console.WriteLine("\n" + new string('-', 60));
for(int i = 0; i < table.Rows.Count; i++) {
for(int j = 0; j < 4; j++) {
Console.Write("{0,-15}", table.Rows[i][j]);
}
Console.WriteLine();
}
}

Listing 32.11 Abrufen von Metadateninformationen

Die resultierende Konsolenausgabe sehen Sie in Abbildung 32.1.

Abbildung

Abbildung 32.1 Ausgabe des Beispiels »GetSchemaTableSample«

Ermitteln des Bezeichners einer Spalte

Möchten Sie den Bezeichner einer bestimmten Spalte in der Ergebnisliste ermitteln, rufen Sie die Methode GetName des SqlDataReader-Objekts auf und übergeben dabei den Index der betreffenden Spalte in der Ergebnisliste. Der Rückgabewert ist eine Zeichenfolge.

Console.WriteLine(reader.GetName(3));

Ermitteln des Index einer Spalte

Ist der Index einer namentlich bekannten Spalte in der Ergebnisliste nicht bekannt, können Sie diesen mit GetOrdinal unter Angabe des Spaltenbezeichners ermitteln.

Console.WriteLine(reader.GetOrdinal("UnitPrice"));

Ermitteln des Datentyps einer Spalte

Sie können sowohl den .NET-Datentyp als auch den Datenbank-Datentyp eines bestimmten Feldes im SqlDataReader abfragen. Interessieren Sie sich für den .NET-Datentyp, rufen Sie die Methode GetFieldType des DataReaders auf, ansonsten GetDataTypeName.

Console.WriteLine(reader.GetFieldType(4));
Console.WriteLine(reader.GetDataTypeName(0));

Beide Methoden erwarten den Ordinalwert der betreffenden Spalte.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
  Zum Katalog
Zum Katalog: Visual C# 2012

Visual C# 2012
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Katalog: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Katalog: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: C/C++






 C/C++


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
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.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de