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 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«

Galileo Computing - Zum Seitenanfang

39.2 Der Lebenszyklus einer Entität im ObjektkontextZur nächsten Überschrift


Galileo Computing - Zum Seitenanfang

39.2.1 Der Zustand einer EntitätZur nächsten ÜberschriftZur vorigen Überschrift

Wie Sie eine Entität ändern, löschen oder hinzufügen und anschließend die Aktualisierungen in die Datenbank schreiben können, haben Sie im letzten Abschnitt gelernt. Bei genauerer Analyse der Listings, die alle die Aktualisierung der Datenbank mit der Methode SaveChanges enthielten, stellt sich die Frage, woher das Entity Framework die Informationen nimmt, ob eine Entität verändert, gelöscht oder hinzugefügt worden ist. Diese Information ist nicht nur entscheidend dafür, welche Entität verändert worden ist, sondern auch dafür, welches SQL-Statement (UPDATE, DELETE oder INSERT) gegen die Datenbank abgesetzt werden muss.

Die Lösung ist sehr einfach: Jede Entität wird durch einen Zustand beschrieben. Auskunft über den aktuellen Zustand der Entität gibt die Eigenschaft EntityState. Diese Eigenschaft ist vom Typ der gleichnamigen Enumeration (siehe Tabelle 39.1).

Tabelle 39.1 Die Werte der Enumeration »EntityState«

Wert Beschreibung

Added

Die Entität wurde dem Objektkontext hinzugefügt.

Deleted

Die Entität wurde aus dem Objektkontext gelöscht.

Detached

Die Entität existiert bereits, wurde aber dem Objektkontext noch nicht hinzugefügt. Dieser Zustand gilt auch für Entitäten, die nicht mehr vom Objektkontext verwaltet werden.

Modified

Die Entität wurde verändert.

Unchanged

Die Entität wurde nicht verändert.


Galileo Computing - Zum Seitenanfang

39.2.2 Das Team der Objekte im ÜberblickZur nächsten ÜberschriftZur vorigen Überschrift

Die Organisation der Zustandsverwaltung der Entitäten gehört zu komplexeren Szenarien des Entity Frameworks. Vielleicht haben Sie im Moment den Eindruck, dass alles vom Objektkontext gesteuert wird. Dem ist aber nicht so, denn bei genauer Betrachtung betreten drei weitere Typen die Bühne des Entity Data Models: ObjectStateManager, EntityKey und ObjectStateEntry. Im Zusammenspiel mit dem Objektkontext bilden diese vier ein Team, das für die gesamte Zustandsverwaltung zuständig ist und uns mit allen erforderlichen Informationen versorgen kann. Auf die genauen Zusammenhänge und den Nutzen für uns bei der Programmierung gehen wir noch genauer ein, aber lassen Sie uns zuerst einen kurzen Blick auf die drei erwähnten Typen werfen.

Der Typ »ObjectStateManager«

Ändert sich der Zustand einer Entität durch Löschen, Hinzufügen oder eine Änderung, müssen die Vorgänge protokolliert und verfolgt werden, damit die Änderungen später an die Datenbank weitergegeben werden können. Dafür ist ein Objekt vom Typ ObjectStateManager verantwortlich, das mit dem ObjectContext fest verbunden ist. Jeder Objektkontext hat nur exakt einen ObjectStateManager, dessen Referenz die Eigenschaft ObjectStateManager des ObjectContext-Objekts liefert:

ObjectStateManager osm = context.ObjectStateManager;

Tatsächlich ist der ObjectStateManager sogar für die meisten Abläufe im Objektkontext verantwortlich. Da jedem Objektkontext genau ein ObjectStateManager zugeordnet wird, ist es nicht verkehrt, davon zu sprechen, dass der Objektkontext die Zustandsänderungen verfolgt.

Der Typ »ObjectStateEntry«

Im Zusammenhang mit der Zustandsverwaltung nur den ObjectStateManager zu erwähnen würde nur einen Teil der Wahrheit bedeuten. Tatsächlich ist mit jeder Entität, deren Zustand verfolgt wird, noch ein Objekt vom Typ ObjectStateEntry verknüpft. Das ObjectStateEntry-Objekt hat nicht nur die Aufgabe, den aktuellen Zustand der verknüpften Entität zu beschreiben, sondern enthält darüber hinaus eine Reihe weiterer Informationen. Beispielsweise können wir aus diesem Objekt neben den aktuellen auch die ursprünglichen Werte der Entitätseigenschaften abrufen oder in Erfahrung bringen, welche Eigenschaften der Entität verändert worden sind.

Der Typ »EntityKey«

Um den Überblick über alle am Lebenszyklus und der Zustandsverwaltung einer Entität beteiligten Objekte zu vervollständigen, muss an dieser Stelle auch noch ein letztes Objekt erwähnt werden: der EntityKey. Dieses Objekt stellt das Bindeglied zwischen einem ObjectStateEntry-Objekt und der zugehörigen Entität dar.


Galileo Computing - Zum Seitenanfang

39.2.3 Neue Entitäten im ObjektkontextZur nächsten ÜberschriftZur vorigen Überschrift

Entitäten, die nicht zum Objektkontext gehören, werden nicht zustandsüberwacht. Das ist zum Beispiel der Fall, wenn Sie eine neue Entität durch den Aufruf des Konstruktors erzeugen:

Product product = new Product();

Das Objekt product gehört in diesem Moment nicht zum Objektkontext. Der Zustand wird mit seiner Eigenschaft EntityState zwar als Detached beschrieben, dennoch hat das Objekt noch kein verknüpftes ObjectStateEntry-Objekt und wird damit auch nicht zustandsverfolgt. Der Aufruf der SaveChanges-Methode würde das neue Objekt folglich nicht als neuen Datensatz in die Tabelle Products eintragen.

Neue Entitäten, die durch den Aufruf des Konstruktors der Entitätsklasse erzeugt werden, müssen mit einer AddXxx-Methode zum Objektkontext hinzugefügt werden. Xxx steht dabei für das gleichnamige EntitySet. In unserem Entity Data Model heißt daher die Methode AddToProducts. Der Methode wird die Referenz auf die neue Entität übergeben, z. B.:

context.AddToProducts(product);

In diesem Moment wird mit der neuen Entität ein ObjectStateEntry-Objekt verknüpft – eine Voraussetzung, damit es später von SaveChanges erfasst werden kann.

Entitäten einem anderen Objektkontext übergeben

Es gibt Szenarien, in denen eine Entität von einem Kontext einem anderen übergeben wird. Wie sich dabei der Zustand einer Entität verändert, kann unter Umständen von entscheidender Bedeutung sein. Sehen Sie sich dazu bitte das folgende Listing an.

using (NorthwindEntities context1 = new NorthwindEntities())
{
Product product = context1.Products.First();
product.ProductName = "Brathering";
Console.WriteLine("Im context1: {0}", product.EntityState);

// Entfernen der Entität aus dem aktuellen Objektkontext

context1.Detach(product);
Console.WriteLine("Ohne Context: {0}", product.EntityState);
using (NorthwindEntities context2 = new NorthwindEntities())
{

// Hinzufügen der Entität zu einem anderen Objektkontext

context2.Attach(product);
Console.WriteLine("Im context2: {0}", product.EntityState);
}
}

Listing 39.7 Eine Entität einem anderen Objektkontext übergeben

Im ersten Schritt wird das erste Produkt aus der Tabelle Products abgefragt und dessen Eigenschaft ProductName geändert. Danach wird der Zustand in die Konsole geschrieben. Er lautet Modified.

Mit der Methode Detach des ObjectContext-Objekts erfolgt im nächsten Schritt die Deregistrierung der Entität bei seinem aktuellen Objektkontext. Es unterliegt danach nicht mehr der vom Objektkontext zur Verfügung gestellten Zustandsüberwachung. Sein Zustand ist Detached. Auch das sehen wir in der Konsolenausgabe.

Anschließend wird ein zweiter Objektkontext erstellt. So wie mit der Methode Detach des Objektkontextes eine Entität der Verwaltung des Objektkontextes entzogen wird, kann mit der Methode Attach eine Entität hinzugefügt werden. Genau das wird mit der Produktreferenz product gemacht, mit darauffolgender Ausgabe des Zustandes. Er lautet nicht, wie möglicherweise erwartet, Modified, sondern Unchanged.

Eine Entität kann nicht gleichzeitig von zwei ObjectContext-Objekten verwaltet werden. Daher ist es notwendig, die Entität zuerst mit Detach bei einem Objektkontext zu deregistrieren, bevor sie einem anderen Objektkontext mit Attach hinzugefügt wird.

Lassen Sie uns die wichtige Erkenntnis, die das Beispiel liefert, allgemein formulieren:

Der Zustand der Entitäten reflektiert nicht den Zustand im Vergleich zum korrespondierenden Datensatz in der Datenbank. Der Entitätszustand ist nur innerhalb seines umgebenden Objektkontextes zu betrachten. Man könnte auch sagen, dass der Objektkontext in der Anwendung hinsichtlich der Entitäten die Rolle der Datenbank übernimmt.

Hätte der Zustand einer Entität Bezug zum korrespondierenden Datensatz in der Datenbank, hätte er sich im zweiten Objektkontext nicht verändert. Stattdessen wird der Zustand aber auf Unchanged gesetzt, weil der neue Objektkontext nichts von der Änderung am Produktbezeichner weiß, die in einem anderen Objektkontext erfolgt ist.


Galileo Computing - Zum Seitenanfang

39.2.4 Die Zustände einer EntitätZur nächsten ÜberschriftZur vorigen Überschrift

Die Mitglieder der Enumeration EntityState beschreiben die möglichen Zustände einer Entität (siehe Tabelle 39.1). Die Zustände können sich ändern. Bis auf das Ändern einer Eigenschaft sind dabei immer Methodenaufrufe im Spiel. Einige habe ich Ihnen zu Beginn des Kapitels schon gezeigt: Beispielsweise DeleteObject und AddToXxx. Beide haben zur Folge, dass der Zustand der Entität automatisch angepasst wird. Im letzten Abschnitt habe ich in Listing 39.7 die Methode Attach benutzt, um eine Entität bei einem Objektkontext zu registrieren, und Detach, um die Entität dem Objektkontext zu entziehen. Auch diese beiden Methoden bewirken eine Zustandsänderung.

Es gibt noch ein paar weitere Methoden, die eine Zustandsänderung bewirken. Dabei können die Zustände nicht x-beliebig wechseln. So ist es zum Beispiel nicht möglich und würde auch keinen Sinn ergeben, eine als Deleted gekennzeichnete Entität in den Zustand Modified zu überführen.

Die Zusammenhänge der einzelnen Zustandsübergänge und die dazugehörigen Methoden können Sie Abbildung 39.2 entnehmen.

Abbildung

Abbildung 39.2 Die Zusammenhänge der Zustandsänderungen im Objektkontext

An dieser Stelle sollten wir kurz auf die einzelnen Zustände im Detail eingehen.

Der Zustand »Unchanged«

Eine Entität ist nach dem Ausführen einer LINQ-Abfrage zuerst im Zustand Unchanged. In diesem Zustand befindet sich eine Entität auch dann, wenn sie mit der Methode Attach bei einem Objektkontext registriert wird. Diese Erfahrung haben wir auch im letzten Listing machen können.

Der Zustand »Modified«

Den Zustand Modified kann eine Entität nur annehmen, wenn sie sich vorher im Zustand Unchanged befunden hat und einen korrespondierenden Datensatz in der Datenbank hat. Dass die Änderung einer Eigenschaft zu diesem Zustand führt, wissen Sie. Es gibt aber mit ApplyCurrentValues und ApplyOriginalValues noch zwei andere Methoden, die wir bisher noch nicht behandelt haben.

Aus dem Modified-Zustand kann eine Entität noch in Deleted oder Detached überführt werden, aber ein Rollback von Deleted bzw. Detached zurück nach Modified ist nicht möglich – zumindest nicht auf direktem Weg.

Der Zustand »Added«

Eine Entität kann nur dann den Zustand Added annehmen, wenn sie vorher Detached war. Ändern Sie eine Added-Entität, wird sie natürlich nicht in den Zustand Modified überführt, da die Entität keinen korrespondierenden Datensatz in der Datenbank hat. Gleiches gilt auch für Deleted.

Der Zustand »Deleted«

Damit eine Entität den Zustand Deleted annimmt, muss auf eine als Unchanged oder Modified gekennzeichnete Entität die Methode DeleteObject aufgerufen werden.

Der Zustand »Detached«

Eine Entität gilt als Detached, solange sie an keinen Objektkontext gebunden ist. Für die Entität bedeutet das, dass Sie alles mit der Entität machen können, für das Entity Data Model ist das alles bedeutungslos. Es gibt keine Zustandsverfolgung, die Entität agiert eigenständig. In Konsequenz dessen bedeutet das aber auch, dass Detached der Standardzustand für jede neu erzeugte Entität ist, die nicht aufgrund einer LINQ-Abfrage erstellt wird.


Galileo Computing - Zum Seitenanfang

39.2.5 Zusätzliche Entitäten in den Datencache ladenZur nächsten ÜberschriftZur vorigen Überschrift

Sollte eine Datenabfrage dazu führen, dass Entitäten zurückgeliefert werden, die sich bereits im Objektkontext befinden, werden die im Objektkontext befindlichen Entitäten nicht ersetzt. Nur Entitäten, die sich zum Zeitpunkt der Abfrage noch nicht im Objektkontext befinden, werden diesem auch hinzugefügt. Gleichzeitig werden auch alle Entitäten zustandsüberwacht. Das ist das Standardverhalten.


Galileo Computing - Zum Seitenanfang

39.2.6 Die Zustandsverfolgung mit »MergeOption« steuernZur vorigen Überschrift

In Abbildung 39.2 ist zu erkennen, dass nicht jede LINQ-Abfrage zwangsläufig zu einer aktivierten Zustandsverfolgung führt. Sie können die Zustandsverfolgung auch abschalten. Das wäre beispielsweise sinnvoll, wenn die Entitäten nicht verändert werden können und nur der Ansicht dienen.

Das Verhalten, wie die von einer Abfrage zurückgegebenen Objekte dem Objektkontext hinzugefügt werden sollen, kann mit der Eigenschaft MergeOption des ObjectQuery- oder ObjectSet-Objekts beeinflusst werden. Die Eigenschaft ist vom Typ der gleichnamigen Aufzählung MergeOption, deren mögliche Werte Sie der Tabelle 39.2 entnehmen können.

Tabelle 39.2 Die Memberliste der Aufzählung »MergeOption«

Membername Beschreibung

AppendOnly

(Standardeinstellung) Objekte, die im Objektkontext nicht vorhanden sind, werden dem Kontext hinzugefügt. Sind die Objekte bereits im ObjectContext, werden sie nicht aus der Datenquelle geladen.

OverwriteChanges

Objekte, die im Objektkontext nicht vorhanden sind, werden an den Kontext angefügt. Wenn ein Objekt bereits im Kontext vorhanden ist, werden die aktuellen und ursprünglichen Werte mit den neuen Werten aus der Datenquelle überschrieben.

PreserveChanges

Die Objekte werden immer aus der Datenquelle geladen. Änderungen an im Kontext befindlichen Objekten werden dabei nicht überschrieben.

NoTracking

Objekte erhalten den Detached-Zustand. Der Zustand dieser Objekte wird nicht vom ObjectStateManager verfolgt.

In Listing 39.8 werden die Produkte abgerufen, die ein bestimmtes Preislimit überschreiten. Aus dieser Menge wird zu Testzwecken das erste Produkt abgerufen, nachdem die Eigenschaft MergeOption des LINQ-Abfrageresultats auf NoTracking festgelegt worden ist. Da das Ergebnis einer LINQ-Abfrage vom Typ IEnumerable ist, muss das Abfrageresultat in den Typ ObjectQuery konvertiert werden, damit darauf die Eigenschaft MergeOption aufgerufen werden kann.

using (NorthwindEntities context = new NorthwindEntities())
{
var query1 = from prod in context.Products
where prod.UnitPrice >= 50
select prod;
((ObjectQuery)query1).MergeOption = MergeOption.NoTracking;

var query2 = query1.First();
Console.WriteLine(query2.EntityState);
}

Listing 39.8 Die Eigenschaft »MergeOption« eines Abfrageresultats

Die Ausgabe des Entitätszustands ist Detached. Kommentieren Sie die Anweisung, die die Eigenschaft MergeOption festlegt, aus, wird der Zustand Unchanged sein, also dem Standard entsprechen.

Bei der Festlegung der Eigenschaft MergeOption auf ein ObjectSet sollten Sie etwas vorsichtiger sein, da es hierbei auf die Position der entsprechenden Anweisung ankommt. Sehen Sie sich hierzu das folgende Listing 39.9 an.

using (NorthwindEntities context = new NorthwindEntities())
{
var query1 = from prod in context.Products
where prod.UnitPrice >= 50
select prod;
context.Products.MergeOption = MergeOption.NoTracking;

var query2 = query1.First();
Console.WriteLine(query2.EntityState);
}

Listing 39.9 Festlegung der Eigenschaft »MergeOption« auf ein »ObjectSet« (falsch)

Wenn Sie das Beispiel ausprobieren, werden Sie feststellen, dass der Zustand der Entität query2 Unchanged ist, obwohl sich im Vergleich zu Listing 39.8 nur sehr wenig geändert hat – nur das der Eigenschaft MergeOption zugrunde liegende Objekt hat sich verändert. Anscheinend ist die Festlegung MergeOption.NoTracking wirkungslos, und es bleibt die Standardvorgabe aktiv.

Um den erwarteten Zustand Detached zu erreichen, muss die Eigenschaft MergeOption vor der Definition der LINQ-Abfrage eingestellt werden, wie in Listing 39.10 gezeigt wird.

using (NorthwindEntities context = new NorthwindEntities())
{
context.Products.MergeOption = MergeOption.NoTracking;

var query1 = from prod in context.Products
where prod.UnitPrice >= 50
select prod;
var query2 = query1.First();
Console.WriteLine(query2.EntityState);
}

Listing 39.10 Festlegung der Eigenschaft »MergeOption« auf ein »ObjectSet« (richtig)

Dieses sehr unterschiedliche Verhalten lässt sich sehr einfach erklären, wenn wir den Ausdruck

from prod in context.Products

genauer analysieren. Mit context.Products wird die Property Products in der Klasse NorthwindEntities des Entity Data Models aufgerufen. Diese Eigenschaft liefert als Rückgabe ein Objekt vom Typ ObjectSet<Product>, wie das folgende Beispiel zeigt:

public ObjectSet<Product> Products {
get {
if ((_Products == null)) {
_Products = base.CreateObjectSet<Product>("Products");
}
return _Products;
}
}

Beim ersten Aufruf von context.Products wird das ObjectSet neu erstellt und danach gecacht. Gecacht werden dabei natürlich auch die Eigenschaften mit den Werten, die in dem Moment für das ObjectSet gesetzt sind. In Listing 39.10 ist das für MergeOption die Einstellung AppendOnly. Das spätere Setzen auf NoTracking hat keine Auswirkungen mehr, weil der Ausdruck query1.First() das gecachte ObjectSet abruft. In Listing 39.10 hingegen wird das ObjectSet mit der gewünschten Einstellung MergeOption.NoTracking gecacht. Deshalb wirkt sich diese Einstellung auf den Zustand von Objekt query2 wie erwartet aus.



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