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

Jetzt 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 39 Entitätsaktualisierung und Zustandsverwaltung
Pfeil 39.1 Aktualisieren von Entitäten
Pfeil 39.1.1 Entitäten ändern
Pfeil 39.1.2 Hinzufügen neuer Entitäten
Pfeil 39.1.3 Löschen einer Entität
Pfeil 39.2 Der Lebenszyklus einer Entität im Objektkontext
Pfeil 39.2.1 Der Zustand einer Entität
Pfeil 39.2.2 Das Team der Objekte im Überblick
Pfeil 39.2.3 Neue Entitäten im Objektkontext
Pfeil 39.2.4 Die Zustände einer Entität
Pfeil 39.2.5 Zusätzliche Entitäten in den Datencache laden
Pfeil 39.2.6 Die Zustandsverfolgung mit »MergeOption« steuern
Pfeil 39.3 Das »ObjectStateEntry«-Objekt
Pfeil 39.3.1 Die Current- und Originalwerte abrufen
Pfeil 39.3.2 Die Methode »TryGetObjectStateEntry«
Pfeil 39.3.3 Abrufen bestimmter Gruppen
Pfeil 39.3.4 Die Methode »GetModifiedProperties«
Pfeil 39.4 Die Klasse »EntityKey«
Pfeil 39.4.1 Die Methoden »GetObjectByKey« und »TryGetObjectByKey«
Pfeil 39.5 Komplexere Szenarien
Pfeil 39.5.1 Die Methode »ChangeState«
Pfeil 39.5.2 Die Methoden »ApplyCurrentChanges« und »ApplyOriginalChanges«

39 Entitätsaktualisierung und ZustandsverwaltungZur nächsten Überschrift

Der Typ ObjectContext spielt im Entity Data Model eine eminent wichtige Rolle. Im vorherigen Kapitel haben wir ein Objekt dieses Typs dazu benutzt, einen Kontext zu beschreiben, um Abfragen gegen eine Datenbank abzusetzen. Die Resultate der Abfragen wurden materialisiert oder, mit anderen Worten, als Objekte an die Laufzeitumgebung zurückgeliefert.

Allein mit der Abfrage von Daten werden Sie sich auf die Dauer nicht zufrieden geben. Sie wollen die Daten oder besser gesagt Entitäten sicherlich auch verändern oder gar löschen oder neue Entitäten erzeugen. Diese Änderungen sollen natürlich auch in der Datenquelle gespeichert werden. Das wird der Schwerpunkt in diesem Kapitel sein. Darüber hinaus werden wir einen Blick in den Hintergrund des Entity Frameworks werfen und verstehen, warum neben dem ObjectContext und den Entitäten im Datencache weitere Objekte eine wichtige Rolle spielen.


Rheinwerk Computing - Zum Seitenanfang

39.1 Aktualisieren von EntitätenZur nächsten ÜberschriftZur vorigen Überschrift


Rheinwerk Computing - Zum Seitenanfang

39.1.1 Entitäten ändernZur nächsten ÜberschriftZur vorigen Überschrift

Änderungen an einer Entität vorzunehmen ist sehr einfach. Zuerst gilt es, sich die Referenz auf die zu editierende Entität zu besorgen. Dazu kann man ein ObjectQuery-Objekt entsprechend filtern oder das gewünschte Objekt direkt abfragen.

using (NorthwindEntities context = new NorthwindEntities())
{
var prod =(context.Products
.Select(p => p)).SingleOrDefault(p => p.ProductID == 1);
if (prod != null) {
prod.ProductName = "Aachener Printen";
prod.UnitsInStock = 0;
// Änderung in die Datenbank schreiben
context.SaveChanges();
Console.WriteLine("Datenbank aktualisiert...");
}
else
Console.WriteLine("Der Artikel wurde nicht gefunden.");
}

Listing 39.1 Änderung einer Entität mit anschließender Speicherung

Ein bestimmter Datensatz eines Produkts kann aus der Datenbank mit der Methode Single oder SingleOrDefault abgefragt werden. Beiden Methoden kann die Filterbedingung als Methodenargument übergeben werden (eine Alternative zur Where-Erweiterungsmethode). Single und SingleOrDefault unterscheiden sich hinsichtlich der Reaktion, wenn das entsprechende Produkt in der Datenbank nicht gefunden wird: Single löst eine Ausnahme aus, während SingleOrDefault den Rückgabewert null liefert.

In der LINQ-Abfrage von Listing 39.1 ist keine Selektion angegeben. Damit handelt es sich bei dem Resultat der LINQ-Abfrage um den Typ Product. Im Code werden die beiden Eigenschaften ProductName und UnitsInStock der Entität geändert.

Mit der Methode SaveChanges des Objektkontextes wird die an der Entität vorgenommene Änderung in die Datenbank geschrieben. Dabei wird die Änderung in ein passendes SQL-UPDATE-Statement umgesetzt. Sie können sich dieses ansehen, wenn Sie im SQL Server Management Studio das Tool SQL Server Profiler starten und ein neues Ablaufprotokoll starten. Sie werden dann das folgende SQL-Statement finden:

exec sp_executesql N'update [dbo].[Products]
set [ProductName] = @0, [UnitsInStock] = @1
where ([ProductID] = @2)
',N'@0 nvarchar(40),@1 smallint,@2 int',@0=N'Aachener Printen',@1=0,@2=1

Erwähnenswert ist, dass nur die Spalten im UPDATE-Statement angegeben sind, die auch tatsächlich einen neuen Wert aufweisen. In unserer Abfrage handelt es sich um ProductName und UnitsInStock. Die WHERE-Klausel hingegen enthält nur die Angabe des Primärschlüssels des betroffenen Datensatzes.

Mehrere Entitäten editieren

Mit SaveChanges werden alle Änderungen, die an einer Entität vorgenommen worden sind, in die Datenbank geschrieben. Nun möchten wir mehrere Entitäten gleichzeitig ändern. Dazu stellen wir uns vor, wir hätten die Absicht, den Lagerbestand aller Artikel, von denen aktuell 20 Stück oder weniger im Lager vorrätig sind, durch eine Nachbestellung auf 100 zu erhöhen. Natürlich könnten wir eine LINQ-Abfrage schreiben, die direkt die Produkte abfragt, die unserer Bedingung genügen. Lassen Sie uns aber annehmen, alle Produkte der Tabelle Products würden sich bereits im Datencache befinden, so dass wir eine weitere LINQ-Abfrage gegen den Datencache absetzen.

using (NorthwindEntities context = new NorthwindEntities())
{
// alle Produkte abfragen
var query = context.Products.Select(p => p).ToList();
// Produkte herausfiltern, deren Lagerbestand <= 20 ist
var prods = query
.Where(p => p.UnitsInStock <= 20)
.Select(p => p);
// Lagerbestand erhöhen
foreach (var item in prods)
item.UnitsInStock = 100;
int count = context.SaveChanges();
Console.WriteLine("Datenbank aktualisiert ({0} Datensätze).", count)
}

Listing 39.2 Lagerbestand mehrerer Artikel gleichzeitig erhöhen

Im ersten Schritt besorgen wir uns mit der Methode ToList alle Artikel. Die Methode sorgt dafür, dass die Abfrage sofort gegen die Datenbank abgesetzt und die Ergebnismenge gebildet wird. Anschließend bilden wir die Menge der Produkte, die unserer Bedingung hinsichtlich des Lagerbestands entsprechen, und erhöhen diesen auf 100.

Die Methode SaveChanges hat einen Rückgabewert, der darüber Auskunft gibt, wie viele Entitäten von der Änderung betroffen sind. Diesen Wert lassen wir uns an der Konsole zur Information ausgeben.


Rheinwerk Computing - Zum Seitenanfang

39.1.2 Hinzufügen neuer EntitätenZur nächsten ÜberschriftZur vorigen Überschrift

Um eine neue Entität zu erzeugen und diese so weit vorzubereiten, dass sie in die Datenbank geschrieben werden kann, sind zwei Schritte notwendig:

  • Im ersten Schritt muss die neue Entität erstellt werden. Dazu wird entweder der Konstruktor aufgerufen oder die CreateXyz-Methode, die von jeder Entitätsklasse bereitgestellt wird.
  • Ist eine neue Entität erzeugt, hat sie noch keinen Bezug zum Objektkontext und liegt noch verwaist im Heap. Daher ist die neue Entität im zweiten Schritt dem Objektkontext bekannt zu geben, damit dieser zu einem späteren Zeitpunkt das Objekt in die Datenbank schreiben kann.

Erzeugen einer neuen Entität

Sehen wir uns zuerst den ersten Schritt an, die Erzeugung eines neuen Entitätsobjekts. Dazu können Sie den parameterlosen Konstruktor der Entitätsklassen aufrufen und weisen den Eigenschaften die gewünschten Werte zu, beispielsweise:

Product product = new Product();
product.UnitsInStock = 0;
product.ProductName = "Schokolade";
product.Discontinued = false;

Neben dem parameterlosen Standardkonstruktor ist in den Entitätsklassen auch eine statische Methode definiert (Factory-Methode), die eine neue Entität der entsprechenden Entitätsklasse erzeugt und deren Referenz über den Rückgabewert bereitstellt. In der Klasse Product lautet diese Methode CreateProduct, in der Klasse Category analog dazu CreateCategory.

Das folgende Codefragment zeigt exemplarisch die vom Assistenten generierte Methode CreateProduct in der Klasse Product.

public static Product CreateProduct(global::System.Int32 productID, 
global::System.String productName,
global::System.Boolean discontinued)
{
Product product = new Product();
product.ProductID = productID;
product.ProductName = productName;
product.Discontinued = discontinued;
return product;
}

Die Factory-Methoden haben im Gegensatz zum Standardkonstruktor den Vorteil, eine Parameterliste zu definieren, in der neben dem Primärschlüssel auch die Eigenschaften berücksichtigt werden, die nicht null sein dürfen. Für die Entität vom Typ Product sind das die Eigenschaften ProductName und Discontinued. Daher erwartet die Factory-Methode Werte für diese beiden Eigenschaften, z. B.:

Product newProduct = Product.CreateProduct(12, "Wurst", false);

Die Factory-Methode garantiert also, dass eine Entität erzeugt wird, die von der Datenbank bei der späteren Aktualisierung in jedem Fall akzeptiert wird, während beim Einsatz des Konstruktors den Eigenschaften explizit ein Wert zugewiesen werden muss.

Hinzufügen zum Objektkontext mit der Methode »AddToXxx«

Nach dem Erzeugen einer neuen Entität muss diese dem Objektkontext übergeben werden, da nur die Entitäten beim Aufruf der Methode SaveChanges erfasst werden, die dem Objektkontext bekannt sind.

Für jede im Entity Data Model definierte Entitätsklasse stellt das Entity Framework dem ObjectContext dazu eine spezielle Methode bereit. In unserem Beispiel beschreibt das Entity Data Model (EDM) die beiden Entitäten Categories und Products. Infolgedessen stellt der Objektkontext die beiden Methoden

  • AddToCategories(Category category)
  • AddToProducts(Product product)

bereit. Die neue Entität wird dabei der Methode als Argument übergeben.

Listing 39.3 zeigt im Zusammenhang das Erzeugen eines neuen Artikels, das anschließende Hinzufügen zum Objektkontext und die Aktualisierung der Datenbank.

using (NorthwindEntities context = new NorthwindEntities())
{
Product product = new Product();
product.ProductName = "Schokolade";
product.Discontinued = false;
// oder: Product product = Product.CreateProduct(99, "Kuchen", false);
context.AddToProducts(product);
context.SaveChanges();
Console.WriteLine("Datenbank aktualisiert...");
Console.WriteLine("Neue ID: {0}", product.ProductID);
}

Listing 39.3 Erzeugen einer neuen Entität mit anschließender DB-Aktualisierung

Im ersten Augenblick scheint der Code des Listings nichts Besonderes zu bieten. Spektakulär ist aber beim genaueren Hinsehen die Ausgabe am Ende des Listings. Zur Erinnerung: Der Primärschlüssel der Tabelle Products wird durch einen Autoinkrementwert beschrieben, der natürlich von der Datenbank erzeugt wird. An der Konsole wird nach der Aktualisierung tatsächlich der Wert angezeigt, den die Datenbank für den neuen Datensatz generiert hat. Demnach wird beim erfolgreichen Hinzufügen einer neuen Entität der zugeteilte Primärschlüssel automatisch vom ObjectContext übernommen. Ein sehr nettes Feature, das uns einiges an Programmcode erspart.

Hinzufügen zum Objektkontext mit der Methode »AddObject«

Es gibt mit der Methode AddObject noch eine zweite Variante, ein neues Objekt dem Objektkontext zu übergeben. Die Methode wird von zwei Klassen bereitgestellt:

  • ObjectContext
  • ObjectSet

Beide Varianten unterscheiden sich nur in der Anzahl der erwarteten Argumente. Während AddObject beim Aufruf auf die Instanz des Objektkontextes die Angabe des Bezeichners der Entitätenmenge und der Referenz auf die hinzuzufügende Entität erwartet, begnügt sich die Methode beim Aufruf auf ObjectSet nur mit der Angabe der neuen Entität.

Um ein neues Produkt, dessen Referenz product lautet, dem Objektkontext bekannt zu geben, können Sie demnach entweder die Anweisung

context.Products.AddObject(product);

oder

context.AddObject("Products", product);

codieren.

Wird ein Datensatz mit einem bereits existierenden Primärschlüssel zur Datenbank hinzugefügt, wird eine InvalidOperationException ausgelöst. Das kann jedoch im Zusammenhang mit den beiden Entitäten Product und Category nicht passieren, da hier die Primärschlüssel durch Autoinkrementwerte beschrieben werden.

Hinzufügen zu Master- und Detailtabelle

Im praktischen Alltag werden häufig Master- und Detailtabelle gleichzeitig ergänzt. Angenommen, es soll der Tabelle Products ein Produkt hinzugefügt werden, das einer Kategorie zugeordnet werden muss, die noch nicht von der Tabelle Categories beschrieben wird. In üblichen Szenarien wird man zuerst die neue Kategorie in die Tabelle Categories eintragen und dann den neuen Schlüsselwert abrufen. Mit diesem kann anschließend auch das Produkt in die Tabelle Products eingetragen werden.

Das Entity Framework ist wesentlich intelligenter, denn SaveChanges macht das alles selbstständig. Das sehen wir uns auch sofort an einem Beispiel an.

using (NorthwindEntities context = new NorthwindEntities())
{
Category newCat = Category.CreateCategory(-1, "Backwaren");
Product newProduct = new Product();
newProduct.ProductID = 0;
newProduct.ProductName = "Jubel's Eierkuchen";
newProduct.Discontinued = false;
newProduct.Category = newCat;
context.AddToCategories(newCat);
context.SaveChanges();
Console.WriteLine("Datenbank aktualisiert ...");
}

Listing 39.4 Gleichzeitige Aktualisierung von Master- und Detailtabelle

Im Listing werden zuerst eine neue Kategorie und ein neuer Artikel erzeugt. Die Referenz auf die neue Kategorie wird der Eigenschaft Category des Artikels zugewiesen, und danach wird die neue Kategorie mit der Methode AddToCategories dem Objektkontext bekannt gemacht. Weil der neue Artikel seinerseits selbst mit der neuen Kategorie in Beziehung steht, ordnet er sich ebenfalls automatisch dem Objektkontext zu.

Der Objektkontext weiß nun, dass zwei Entitäten hinzugefügt worden sind, die miteinander in Beziehung stehen, und aktualisiert beim Aufruf von SaveChanges in der erforderlichen Reihenfolge: Zuerst fügt er die neue Kategorie zur Datenbank hinzu, anschließend das neue Produkt.

Davon können wir uns im SQL Server Profiler überzeugen. Es werden der Reihe nach die entsprechenden SQL-UPDATE-Statements abgesetzt. Als Erstes wird

exec sp_executesql N'insert [dbo].[Categories]([CategoryName], 
[Description], [Picture])
values (@0, null, null)
select [CategoryID]
from [dbo].[Categories]
where @@ROWCOUNT > 0 and [CategoryID] = scope_identity()',
N'@0 nvarchar(15)',@0=N'Backwaren'

abgesetzt, danach

exec sp_executesql N'insert [dbo].[Products]([ProductName], ...)
values (@0, null, @1, null, null, null, null, null, @2)
select [ProductID]
from [dbo].[Products]
where @@ROWCOUNT > 0 and [ProductID] = scope_identity()',N'@0 nvarchar(40),@1 int,@2
bit',@0=N'Jubel''s Eierkuchen',@1=10,@2=0

Auch hier werden automatisch die neuen, von der Datenbank generierten Primärschlüssel bezogen.


Rheinwerk Computing - Zum Seitenanfang

39.1.3 Löschen einer EntitätZur nächsten ÜberschriftZur vorigen Überschrift

Kommen wir nun zur dritten Aktualisierungsmöglichkeit, dem Löschen. Die Methode dazu lautet DeleteObject, die Sie entweder auf das ObjectContext-Objekt aufrufen können oder auf das ObjectSet. Damit wären die beiden folgenden Anweisungen möglich, falls product die Referenz auf die zum Löschen anstehende Entität beschreibt:

context.DeleteObject(product);
context.Products.DeleteObject(product);

Natürlich wollen wir uns auch dazu ein komplettes Listing ansehen.

using (NorthwindEntities context = new NorthwindEntities())
{
var prod = context.Products
.Select(p => p).First(p => p.ProductID == 78);
context.DeleteObject(prod);
context.SaveChanges();
Console.WriteLine("Artikel gelöscht.");
}

Listing 39.5 Löschen einer Entität

Nach dem Aufruf von SaveChanges ist das betreffende Produkt in der Datenbank gelöscht.

Sollten Sie das Beispiel des Listings 39.5 erfolgreich ausführen wollen, sollten Sie berücksichtigen, dass Sie vorher auch einen neuen Artikel mit der ProductID = 78 hinzugefügt haben, denn ursprünglich weist die Tabelle Products nur Produkte bis zum Schlüsselwert 77 auf.

Löschen von in Beziehung stehenden Daten

Beim Löschen eines Datensatzes kann es passieren, dass gegen die referenzielle Integrität verstoßen wird, weil der zu löschende Datensatz in Beziehung zu mindestens einem weiteren Datensatz in einer anderen Tabelle steht und die Beziehung eine Löschweitergabe nicht erlaubt. In diesem Fall wird eine Ausnahme vom Typ UpdateException ausgelöst. Das würde beispielsweise bei dem Versuch passieren, aus der Northwind-Datenbank einen Artikel zu löschen, der Bestandteil einer Bestellung und somit in der Tabelle Order_Details eingetragen ist.

Um trotzdem das Ziel zu erreichen und den Artikel zu löschen, ist es notwendig, auch die in Beziehung stehenden Einträge aus der Tabelle Order_Details zu löschen. Dazu wäre zuerst ein entsprechendes Entity Data Model Voraussetzung, in dem zumindest die beiden Entitäten Product und Order_Detail enthalten sind. Sie können dazu das bereits vorhandene EDM um die erforderliche zusätzliche Entität ergänzen, indem Sie im Bereich des Designers mit der rechten Maustaste das Kontextmenü öffnen und hier Modell aus der Datenbank aktualisieren... auswählen. Bereits im nächsten Schritt können Sie das EDM um die Entität Order_Details ergänzen (siehe Abbildung 39.1).

Abbildung

Abbildung 39.1 Entity Data Model (EDM) für das Listing 39.6

Den Ablauf zum Löschen des Artikels sehen Sie im Listing 39.6.

using (NorthwindEntities context = new NorthwindEntities())
{
var prod = context.Products.First(p => p.ProductID == 2);
var orders = context.Order_Details
.Where(order => order.ProductID == prod.ProductID);
context.DeleteObject(prod);
foreach (var item in orders)
context.DeleteObject(item);
context.SaveChanges();
Console.WriteLine("Artikel (samt der Bestellungen) gelöscht.");
}

Listing 39.6 Löschen von in Beziehung stehenden Daten

Zuerst wird das zu löschende Produkt in den Objektkontext geladen, und mit dessen ID-Wert werden die entsprechenden Bestellungen abgerufen. Normalerweise würde man zuerst die Bestellungen löschen und anschließend das Produkt, aber beim Entity Framework spielt die Löschreihenfolge keine Rolle: Der Objektkontext sorgt für die richtige Löschreihenfolge beim Ausführen der Methode SaveChanges. Sie können sich davon wieder im Ablaufverfolgungsprotokoll des SQL Server Profilers überzeugen. Demnach werden zuerst alle Bestellungen mit

exec sp_executesql N'delete [dbo].[Order Details]
where (([OrderID] = @0) and ([ProductID] = @1))',
N'@0 int,@1 int',@0=11077,@1=2

gelöscht. Anschließend kommt es zum Löschen des entsprechenden Artikels.

exec sp_executesql N'delete [dbo].[Products]
where ([ProductID] = @0)',N'@0 int',@0=2

Ist die Beziehung mit Löschweitergabe zwischen zwei Tabellen definiert, ist es sehr einfach, diese zu nutzen. Angenommen, in der Northwind-Datenbank wäre das bei der Beziehung zwischen den beiden Tabellen Products und Order_Details der Fall. Dann würde es genügen, die betreffende Product-Entität im Objektkontext zu löschen und die Methode SaveChanges aufzurufen.

var product = context.Products.First(prod => prod.ProductID == 32);
context.DeleteObject(product);
context.SaveChanges();

In der Datenbank würden automatisch alle entsprechenden Einträge in der Tabelle Order_Details ebenfalls gelöscht.



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 C# 2012

Visual C# 2012
Jetzt Buch bestellen


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

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






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


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






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
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.


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