Zur Zeit wird gefiltert nach: René
Filter zurücksetzen

Entity Framework 4.3 - Building Blocks oder wie steuer ich die Datenbankversion

Gelegentlich kommt es vor, dass die Datenbankversionen pro Umgebung unterschiedlich sein können. Bei meinen ersten versuchen ist mir das mit den SQL-Server Versionen 2005 und 2008 so ergangen.

Sofort ersichtlich wurde das, wenn die folgende Fehlermeldung im Log zu sehen war:

System.ArgumentException: The version of SQL Server in use does not support datatype 'datetime2'

Um dies in den Griff zu bekommen gibt es das Attribut "ProviderManifestToken" in der EDMX-Datei. Mit dem ERM-Ansatz lassen sich, neben unterschiedlen Datenbanken, auch unterschiedliche Versionen einer Datenbank verwalten und mappen. Ein sehr interessanter Ansatz bei der Realisierung von Standardsoftware.

Nun stellt sich die Frage, wie mache ich das in Code First mit Schema Migrations?

Der Schlüssel liegt dabei in der Klasse DbModelBuilder. Beim erstellen kann damit die Datenbankversion definiert werden.


// default
var model = builder.Build(connection);

// with version
var model = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2005"));

Gerade mit der nächsten Version von SQL Server 2012 wird es sicherlich ähnliche Probleme geben können, wenn die Systemumgebungen trotz ITIL nicht ganz so synchron sind. Bei der erstmaligen Erstellung des Models wird das sicherlich nicht von Bedeutung sein, wohl aber bei Schema Migrations.

Im Blogbeitrag von Arthur Vickers finden sich noch andere interessante Punkte die interessant sind, so auch die Aussage das Pluggable Conventions für den Durchschnittsentwickler frühstens mit EF6 nutzbar werden, wenn überhaupt.

Weitere Informationen zum Thema:

Entity Framework 4.3 Mapping Szenarien

Vor ein paar Wochen wurde über Twitter gefachsimpelt, welche Vererbungsstrategie Standard bei Code First ist. Es kam sehr schnell die Antwort TPT. Da ich diesen Bereich mit der Version 4.1 durchgetestet habe und eigentlich TPH der Standard ist, wollte ich nun überprüfen, ob sich etwas zur Version 4.3 geändert hat.

Mit Partick Weibel hatte ich vor 2 Jahren im Bereich der Mapping Strategien eine Präsentation zum Thema "Übersicht zwischen NHibernate und dem Entity Framework" bei der .NET User Group Bern gehalten. Der Schwerpunkt lag dabei auf Business Value, weniger auf Religion.

Diese Beispiele habe ich auch für den Code First Ansatz mit dem Entity Framework nachgeführt, um die Unterschiede zwischen den Vorgehensweisen Bottom Up (DB First), Middle Out (Model First) und Top Down (Code First) zu visualisieren. Herausgekommen ist dabei folgende Übersicht:

Abbildung 1
Abbildung 1 Mapping Szenarioen (mb = Fluent API)

Diese Beispiele habe ich nun auf die Version 4.3-1 aktualisiert und die Standardvererbung überprüft. Es ist immer noch die Strategie TPH. Meine Übersicht ist auch mit der Version 4.3 noch aktuell. ;-)

Im Bereich der Vererbungshierarchie soll es bei TPC Verbesserungen gegeben haben. Bisher war es so, dass nur einfache TPC-Szenarien möglich waren. Daran ändert sich auch nichts. Folgender Code lässt sich auch nicht mit der Version 4.3 mappen:


  public abstract class Product
  {
    public int Id { get; set; }

    [StringLength(50)]
    [Required]
    public string Name { get; set; }

    [StringLength(400)]
    public string Description { get; set; }
  }

  public class Book : Product
  {
    [StringLength(10)]
    [Required]
    public string ISBN10 { get; set; }

    [StringLength(13)]
    [Required]
    public string ISBN13 { get; set; }

    public int LanguageCD { get; set; }

    [Required]
    public int Pages { get; set; }
  }

  public class EBook : Book
  {
    [Required]
    public string Filename { get; set; }
  }

  public class Hardcover : Book
  {
    [StringLength(20)]
    [Required]
    public string Size { get; set; }

    [Required]
    public double Weight { get; set; }
  }

Im Designer ist dieser Variante auch nur über manuelle Anpassungen im EDMX-File möglich, aber es funktioniert.

Die Mapping Szenarien für Code First stehen auf der Website der .NET User Group Bern zur Verfügung, ein Update auf 4.3.1 muss aber noch gemacht werden. ;-) Bei mir sind die paar Tests auch mit EF 4.3.1 im grünen Bereich.

Abbildung 2
Abbildung 2 Mapping-Szenarien Tests mit EF 4.3.1

Entity Framework - Ein neuer Workaround für 2nd Level Cache mit dem DbContext

Bisher habe ich den 2nd Level Cache nur über einen Umweg über den ObjectContext zum laufen gebracht. Pawel Kadluczka vom EF-Team hat Ende März einen weiteren Ansatz in seinen Blog veröffentlicht, der ohne den ObjectContext auskommt.

Dieser kann auch in Verbindung mit SchemaMigrations zusammen arbeiten, wenn die Tricks und Kniffe im Beitrag beachtet werden.

Wenn das EF-Team an solchen Workarounds rumbastelt, kann davon ausgegangen werden, dass der 2nd Level Cache weiterhin kein Bestandteil des Kerns von EF werden wird. Zum Beitrag geht es hier lang.

Weitere Informationen zum Thema

15.03.2012
22:54

Sharepoint Deployment API zwischen Version 2007 und 2010

Meine Migrationsstory geht weiter. Nachdem der Export vorlag, stand ich das erste Mal an, weil mich bei einem Testimport die Fehlermeldung:

The version of the package 12.0.10.0 is different from the current version this program supports, 14.0.0.0

begrüsste. Nach ein bisschen suchen fand ich einen Ansatz. Die Package Files, speziell die SystemData.xml muss angepasst werden, damit sich der Inhalt aus Sharepoint 2007 in Sharepoint 2010 importieren lässt.

In der XML-Datei muss dazu auf SchemaVersion-Ebene die Version, dass aktuelle Patchlevel (Build) und die Datenbankversion (DatabaseVersion) angegeben werden. Nachfolgendes XML zeigt einen Ausschnitt aus der SystemData.xml:


<?xml version="1.0" encoding="utf-8"?>
<SystemData xmlns="urn:deployment-systemdata-schema">
    <SchemaVersion Version="14.0.0.0" Build="14.0.6109.5002" DatabaseVersion="133739" SiteVersion="0" ObjectsProcessed="27" />
    <ManifestFiles>
        <ManifestFile Name="Manifest.xml" />
    </ManifestFiles>
    <SystemObjects>
        ...
    </SystemObjects>
    <RootWebOnlyLists />
</SystemData>

Müssten die Daten nicht noch bereinigt und transformiert werden, wäre ich bereits am Ende. Nun geht es daran, die XML-Dateien so aufzubereiten, damit die Daten in das Format der neuen Lösung des Zielsystems importiert werden können.

ETL geht auch einfacher, aber nicht unbedingt wenn Sharepoint im Spiel ist. ;-)

Weitere Informationen zum Thema:

Parallelisierung wenn eine relationale Datenbank im Spiel ist

Nachdem ich mir das erste Mal eine CLR-Funktion für eine Datenmigration gebaut habe, geht es nun daran Codeteile zu parallelisieren, damit die Migrationsdauer verkürzt werden kann. Ein paar Herausforderungen dabei:

  • Ich habe die Auflage das Ganze in .NET 3.5 zu entwickeln, sodass ich die TPL nicht nutzen kann.
  • Direkte Insert, Update und Delete-Anweisungen dürfen nicht ausgeführt werden. Es muss die Sharepoint Content Deployment API verwendet werden.

Im Blogpost fand ich einen interessanten Ansatz, wie in .NET 3.5 eine parallele Schleife realisiert werden kann.

Also den ersten Test erstellt. Eine Stub-Methode die 10 Sekunden wartet, geschrieben und 5-mal aufgerufen. Testkriterium: Ausführungsdauer weniger als 15 Sekunden bestehen, funktioniert.

Anschliessend den integrativen Test in Verbindung mit einer Datenbank. Testkriterium: Auditinformationen in Datenbank schreiben nicht erfüllt, tatsächlich:

Transaction (Process ID XX) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, …

Ein Codestück, das die Verbindung zur Datenbank herstellt, hat folgenden Aufbau:


public static void ExecuteNonQuery(SqlCommand cmd)
{
    try
    {
        using (var conn = GetSqlConnection())
        {
            cmd.Connection = conn;
            cmd.ExecuteNonQuery();
         }
    }
    catch (Exception ex)
    {
       log.Error(ex.Message, ex);
        throw;
    }
}

Als ersten Ansatz stellte ich dieses Codestück um und machte einen asynchronen Aufruf daraus.

Es dauerte unwesentlich länger, aber auch dieser Code erzeugte Deadlocks auf der Datenbank. In diesem Moment kam ich zum Schluss: So, genug gebastelt jetzt wird analysiert wer bzw. was diese Deadlocks auf der Datenbank auslösen. Wenn ich mit dem SQL Server arbeite, nutze ich üblicherweise den SQL Server Profiler für diese Zwecke.

Dieser kann über das SQL Server Management Studio (SSMS) unter dem Menüpunkt Tools gestartet werden. Nach der Verbindung zur Datenbank kann auf der ersten Dialogmaske das Template TSQL_Locks ausgewählt werden.

Abbildung 1
Abbildung 1 Einstellungen für Deadlock-Tracing

Unter dem zweiten Tab können weitere Einstellungen vorgenommen werden, darauf gehe ich nicht näher ein. Mit klick auf die Schaltfläche "Run" wird die Ablaufverfolgung gestartet.

Nach dem Start des Integrationstests wurde alles aufgezeichnet und es dauerte nicht lange, bis die ersten Meldungen im Tracelog erschienen.

Abbildung 2
Abbildung 2 Informationen im Trace über Deadlocks
Abbildung 3
Abbildung 3 Grafische Übersicht, welcher Prozess zum Opfer erklärt wurde

Mit diesen Informationen lässt sich im ersten Augenblick nichts anfangen, der Deadlock Graph ist noch interessant, da hier ersichtlich wird, welcher Prozess durch den aktuellen zum Opfer erklärt wurde.

Nun stellt sich die Frage, welcher Befehl ausgeführt wurde. Dies lässt sich über die Object Id ermitteln. Im Trace steht die Object ID 693577509. Wer sich dahinter versteckt, lässt sich mit folgendem SQL-Befehl ermitteln:

Der Deadlock Graph zeigt zudem noch nützliche Informationen an, mit denen sich auch die Befehle ermitteln lassen. In meinem Beispiel trat der Deadlock während eines Inserts in die Log-Tabelle auf.

Abbildung 4
Abbildung 4 Angaben welcher Prozess zum Deadlock führte

SELECT
	name
	, type
	, type_desc
 FROM sys.objects
 WHERE object_id IN (693577509)

Wer das obige Codebeispiel nochmals betrachtet sieht, dass die Methode statisch ist. Hier ging ich von der Annahme aus, dass dieser Ansatz "Thread Safety" ist. Um das Problem zu beheben, habe ich die statische Methode wie folgt angepasst:


static readonly object locker = new object();

public static void ExecuteNonQuery(SqlCommand cmd)
{
    try
    {
        lock (locker)
        {
            using (var conn = GetSqlConnection())
            {
                cmd.Connection = conn;
                cmd.ExecuteNonQuery();
            }
        }
    }
    catch (Exception ex)
    {
        log.Error(ex.Message, ex);
        throw;
    }
}

Nach dieser Anpassung waren die Deadlocks verschwunden. Ganz parallel arbeitet dieser Code natürlich nicht mehr, es wird sich also nicht der komplette Code parallelisieren lassen.

Noch eine Anmerkung zum Schluss: Vergesst vor lauter Unit-Testing mit Mocks und Fakes die Integrationstests mit zufälligen und korrupten Daten nicht. ;-)

Weitere Informationen zum Thema:

Translate this page

Kategorien

  • [-].NET Development (215)
  • [-]Datenbank (26)
  • HTML (1)
  • Konfiguration (12)
  • Mind Map (10)
  • Off-topic (9)
  • Open Source (3)
  • Qualität (7)
  • Sharepoint (6)
  • Sicherheit (2)

Archiv

Social Bookmarking

Bookmark bei: Mr. Wong Bookmark bei: Webnews Bookmark bei: Icio Bookmark bei: Oneview Bookmark bei: Linkarena Bookmark bei: Favoriten Bookmark bei: Seekxl Bookmark bei: Favit Bookmark bei: Social Bookmarking Tool Bookmark bei: Power Oldie Bookmark bei: Bookmarks.cc Bookmark bei: Newskick Bookmark bei: Newsider Bookmark bei: Linksilo Bookmark bei: Readster Bookmark bei: Folkd Bookmark bei: Yigg Bookmark bei: Digg Bookmark bei: Del.icio.us Bookmark bei: Reddit Bookmark bei: Simpy Bookmark bei: StumbleUpon Bookmark bei: Slashdot Bookmark bei: Netscape Bookmark bei: Furl Bookmark bei: Yahoo Bookmark bei: Spurl Bookmark bei: Google Bookmark bei: Blinklist Bookmark bei: Blogmarks Bookmark bei: Diigo Bookmark bei: Technorati Bookmark bei: Newsvine Bookmark bei: Blinkbits Bookmark bei: Ma.Gnolia Bookmark bei: Smarking Bookmark bei: Netvouz Information