Archiv für den Monat Dezember 2013

Entity Framwork 6 provider wechsel – MSSQL und MySQL


Oft muss eine Software sehr flexibel gestaltet werden, damit diese so vielen Kundenwünschen wie möglich entspricht. Hier muss z.B. auch die DB Schnittstelle eine entsprechende Flexibilität aufweisen, damit man nicht nur MS SQL Server unterstützt sondern z.B. auch MySQL.

Wenn man also eine Software erstellen möchte die auf unterschiedlichen Datenbanken laufen soll, sucht man sich am Besten ein passendes Framework wie das Entity Framework. Jetzt muss man noch darauf achten, das man in seinen Modeldaten nur Datentypen verwendet, die sowohl MS SQL und MySQL unterstützten. MySQL unterstützt z.B. kein “varchar(max)”, hier muss dann entsprechend abgewogen werden welcher Datentyp bzw. welche Länge wirklich benötigt wird.

Der Providerwechsel bzw. die Umsetzung, kann mit dem Entity Framework sehr einfach durchgeführt werden. Hier muss aber darauf hingewiesen werden, das der Release von EF6 erst vor kurzem war und es z.B. mit Visual Studio 2013 zu diversen Problemen kommen kann, wenn man ein passendes MySQL Script generieren möchte.

1. Installieren der Voraussetzungen

Als erstes benötigen wir einen aktuellen Connector für MySQL in der Version 6.8.1.0 oder höher, zu finden unter: http://dev.mysql.com/downloads/connector/net/

2. Erstellen einer Beispiel Konsolenanwendung

Legen Sie eine Konsolenanwendung für .NET 4 an und fügen Sie der die folgenden Verweise hinzu:

  • MySql.Data.dll (Version 6.8.1.0 oder höher)
  • MySql.Data.Entity.EF6.dll (Achtung aufpassen für .NET 4.0 und nicht 4.5 – für unser Beispiel)
  • EntityFramework.dll (Version 6+)
  • EntityFramework.SqlServer
  • System.Data.Entity
  • System.Configuration

Die MySql DLLs wurden vom Connector für MySql installiert und sollte man unter den Standard Assemblies finden.

3. Anlegen der passenden Datenbanken in MySQL und MS SQL

Der einfachste Weg um zwei “identische” Datenbanken für MySQL und MS SQL zu bekommen, ist es ein Model zu erstellen und dann entsprechend die SQL Skripte vom Visual Studio erstellen zu lassen.

Das Erstellen eines MySQL Skriptes über das Visual Studio ist aktuell aber noch sehr “fehleranfällig” und ist mir nur in einer bestimmten Konstellation gelungen. Dazu habe ich auf einer Virtuellen Maschine nur Visual Studio 2012 und dotConnect für MySQL installiert. Dann habe ich das entsprechende Datenmodell erstellt und darauf geachtet, das ich nur Datentypen verwende die auch von beiden DB Systemen unterstützt werden. Da ich Visual Studio 2012 verwendet habe, handelte es sich hier auch um ein EF5 Model! – dies sollte aber nur zum erstellen der SQL Skripte verwendet werden.

Wenn man dann in den Eigenschaften der EDMX Datei die DDL Genration Template auf “Devart SSDLToMySql.tt” stellt und dann im Model auf “Generate Database from Model” klickt wird einem das passende MySQL Script erstellt.image

Mit dem Originaltemplate “SSDLToSQL10.tt” erhält man natürlich das passende MS SQL Script.

Ich denke wenn die einzelnen Anbieter noch etwas Zeit bekommen, ist es bestimmt bald möglich alles direkt mit EF6 in V2013 auszuführen. Dies war mir aber mit den aktuellen Treiberversionenversionen nicht möglich.

4. Passende MySql SSDL extrahieren

Damit wir später auch entsprechende Abfragen auf der MySql Datenbank ausführen können, benötigen wir noch die passende SSDL von der MySql Datenbank. Denn wenn wir später zwischen MySql und MS Sql Datenbank wechseln wollen, benötigen wir eine SSDL für die MySql Datenbank und eine SSDL für die MS SQL Datenbank. In meinem Beispiel extrahieren wir die SSDL für die MySql Datenbank und verwenden die Standard SSDL aus dem EDMX Model für die MS SQL Datenbank.

Die SSDL ist in der EDMX Model Datei “verpackt”. Als erstes benötigen wir eine EDMX Datei bei der wir das Model aus der MySql Datenbank erstellt haben. Dann öffnet man die EDMX Datei mit einem einfachen SQL Editor über das Visual Studio

image

Und wir extrahieren den Abschnitt nach “<!– SSDL content –>” von “<Schema …>” bis zum “</Schema>” Ende und erstellen eine neue Datei z.B. EFModel.MySql.ssdl, hier fügen wir als erste Zeile folgendes ein

<?xml version="1.0" encoding="utf-8"?>

Der Rest wird mit unseren XML Daten aus dem EDMX gefüllt, das ganze könnte dann z.B. folgendermaßen aussehen

<?xml version="1.0" encoding="utf-8"?>
<Schema Namespace="testDbModel.Store" 
        Alias="Self" 
        Provider="MySql.Data.MySqlClient" 
        ProviderManifestToken="5.6" 
        xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" 
        xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl">
  <EntityContainer Name="testDbModelStoreContainer">
    <EntitySet Name="person" EntityType="testDbModel.Store.person" store:Type="Tables" Schema="testdb" />
  </EntityContainer>
  <EntityType Name="person">
    <Key>
      <PropertyRef Name="Name" />
    </Key>
    <Property Name="Name" Type="char" Nullable="false" MaxLength="10" />
    <Property Name="Vorname" Type="char" MaxLength="10" />
    <Property Name="Age" Type="int" />
    <Property Name="Geburtsdatum" Type="datetime" />
    <Property Name="IsMale" Type="bit" />
  </EntityType>
</Schema>

Hier ist wichtig, das als Provider “MySql.Data.MySqlClient” eingetragen ist. Sollte dies nicht der Fall sein, dann wurde das Model aus der falschen DB erstellt. Die Datei legen wir mit im EF Projekt im Selben Pfad wie die EDMX ab und stellen unter den Eigenschaften der Datei ein, das diese mit ins Ausgabeverzeichnis kopiert werden soll.

image

Auf die SSDL selbst greifen wir erst wieder im Connectionstring zu.

5. Anpassen der App.config (Connectionstring erstellen und Provider hinzufügen)

Als nächstes müssen wir die App.config anpassen, denn für EF6 gibt es hier weitere Einstellungen die vorgenommen werden müssen. Dazu gehört es die passenden Provider für MS SQL und MySQL in der App.config einzutragen, die Angabe des Providers wird ab EF6 benötigt.

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  <providers>
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    <provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, mysql.data.entity.EF6" />
  </providers>
</entityFramework>

Auch die jeweils passenden Connectionstrings für die MySQL und MS SQL Datenbank fügen wir der App.config hinzu. Hier ist der entsprechende “provider” angepasst, der zugehörige “provider connection string” und die SSDL für MySql angepasst.

  <connectionStrings>
    <add name="MsSQLConn" connectionString="metadata=res://*/EFModel.csdl|res://*/EFModel.ssdl|res://*/EFModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=172.168.0.1\SQL2008R2;initial catalog=testDb;persist security info=True;user id=sa;password=meinPasswort;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
    <add name="MySQLConn" connectionString="metadata=EFModel.MySql.ssdl|res://*/EFModel.csdl|res://*/EFModel.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;user id=root;password=meinPasswort;persistsecurityinfo=True;database=testDb&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>

Im Connectionstring für MySql muss die passende SSDL für “EFModel.MySql.ssdl” eingetragen werden, hier ist es wichtig das diese ohne “res:/*//…” eingetragen wird. Die Datei wird nur vom EF gefunden, wenn diese auch auf “Copy to Output Directory” gestellt wurde, denn sonst kommt es beim Ausführen von MySql Anweisungen z.B. zu folgendem Fehler:

“System.Data.MetadataException: The specified metadata path is not valid. A valid path must be either an existing directory, an existing file with extension ‚.csdl‘, ‚.ssdl‘, or ‚.msl‘, or a URI that identifies an embedded resource. …”

Wenn man keine extra SSDL z.B. für MySql einbindet, dann kommt es bei SQL Abfragen zu folgendem Fehler:

„Unable to cast object of type ‚MySql.Data.MySqlClient.MySqlConnection‘ to type ‚System.Data.SqlClient.SqlConnection‘.“

UPDATE: Es ist auch möglich die MySql.ssdl Datei mit als Resource in die DDL einzubinden. Wichtig ist, dass dann unter Metadata der Namespace in dem sich die ssdl befindet mit vor den Namen der ssdl geschrieben wird. D.h. wenn die DLL den Namespace “efdata” hat und die ssdl den Namen “EFModel.MySql.ssdl” dann sieht der Metadata Eintrag für die MySql.ssdl folgendermaßen aus: “res://*/efdata.EFModel.MySql.ssdl|res://*/edoModel.csdl…”. Sollte dies nicht funktionieren, dann muss die DDL in der die ssdl als Resource eingebettet wurde mit z.B. ILSpy angeschaut werden und dort sieht man dann auch den genauen Namen der eingebetteten ssdl Resource.

6. Verwenden der Connectionstrings

Ich habe mein EF Model entsprechend erweitert, das ich den Connectionstring direkt übergeben kann. Daher kann ich den passenden Connectionstring direkt aus der App.config verwenden um z.B: eine neue Person der MS SQL Datenbank hinzuzufügen.

string connectionString = ConfigurationManager.ConnectionStrings["MsSQLConn"].ConnectionString;
testDbEntities entities = new testDbEntities(connectionString);
entities.Person.Add(new Person() { Age = 23, Geburtsdatum = DateTime.Now, IsMale = true, Name = "Test", Vorname = "Blubb"});
entities.SaveChanges();

Das einzige was angepasst werden muss, wenn man die Daten der MySQL Datenbank hinzufügen möchte ist, das “MsSQLConn” in ein “MySQLConn” zu ändern, um den MySQL Connectionstring zu ermitteln.

Advertisements