Entity Framework: Setzen des Concurrency Mode für alle Spalten in der EDMX-Datei

Der Dotnet-Doktor  –  0 Kommentare

Programmcode für ein Werkzeug, das die Concurrency-Mode-Eigenschaft aller Spalten im Entity Data Model auf "Fixed" setzt.

In der Grundeinstellung verfolgt Microsofts Entity Framework bei schreibenden Datenzugriffen die Strategie "Der Letzte gewinnt". Das ist jedoch in der Praxis oft kein gangbarer und für die Nutzer auch kein akzeptabler Weg. Man kann aber bei Entity Framework das "optimistische Sperren" (wie beim ADO.NET Dataset) aktivieren.

Beim Code-based Modeling erfolgt das durch Annotation mit dem ConcurrencyCheckAttribute egal, ob die Entitätsklasse selbst geschrieben oder aus einer bestehenden Datenbank von Visual Studio per Reverse Engineering generiert wurde. Lästiger ist es beim Einsatz des "Entity Data Model"-Designers für "Database First" oder "Model First": Hier muss der Softwareentwickler jedes Property im Designer anklicken und dort die Eigenschaft Concurrency Mode auf den Wert "Fixed" festlegen. Leider hat Microsoft in den "Entity Framework"-Designer keine Möglichkeit eingebaut, den Standardwert für die Eigenschaft für Concurrency Mode auf den Wert "Fixed" zu bestimmen.

Wenn man den Concurrency Mode nicht manuell für jedes Property setzen möchte (was nicht nur lästig ist, sondern auch fehleranfällig, weil man leicht ein Property übersehen kann), dann muss man sich ein Werkzeug schreiben, dass die EDMX-Datei ändert. Das ist keine Hexerei, sondern recht einfach, da die EDMX-Datei im XML-Format vorliegt. Die Lösung zeigt das nachstehende Listing. Aufrufen kann man diesen Code dann mit

ConcurrencyModeUtil.ChangeConcurrencyMode(@"x:\...
\Modell.edmx", ConcurrencyMode.Fixed)

in einer Kommandozeilenanwendung, die man als in Visual Studio als Pre-Build-Event in die Projekteigenschaften einträgt. Und schon ist immer sichergestellt, dass alle Properties den Concurrency Mode korrekt gesetzt haben.

  /// <summary>
/// Zur Ausführung zur Entwicklungszeit
/// Ändert alle Propertes im Conceptual Model einer EDMX-Datei
/// auf ConcurrencyMode = fixed oder = none
/// </summary>
/// <param name="edmxPath">Pfad zur EDMX-Datei.</param>
/// <param name="value">ConcurrencyMode none oder fixed.</param>
public static void ChangeConcurrencyMode(string edmxPath,
ConcurrencyMode mode)
{

// öffne EDMX-Datei als XML-Dokument
XDocument xmlDoc = XDocument.Load(edmxPath);

// Suche Element <ConceptualModels>
var conceptualModel = xmlDoc.Descendants().SingleOrDefault
(p => p.Name.LocalName == "ConceptualModels");

// Suche alle Unterelemente <Property>, wo der ConcurrencyMode nicht dem
// gewünschten Wert entspricht
IEnumerable<XElement> properties =
from el in conceptualModel.Descendants()
where el.Name.LocalName == "Property"
&& (string)el.Attribute("ConcurrencyMode") != mode.ToString()
select el;

bool modified = false;

// Setze ConcurrencyMode in den gefundenen Properties
foreach (XElement el in properties)
{
modified = true;
el.SetAttributeValue("ConcurrencyMode", mode.ToString());
Console.WriteLine(el.Attribute("Name") + ": " +
el.Attribute("ConcurrencyMode"));
}

// Speichern, falls es Änderungen gab
if (modified)
{
xmlDoc.Save(edmxPath);
Console.WriteLine("Datei " + edmxPath + " wurde geändert!");
}
}
}
}