4. Fallstudie mit MySQL 5.5.28
4.1. Installation der Tools
Folgende Tools müssen installiert werden:
- das DBMS: [http://dev.mysql.com/downloads/];
- ein Verwaltungstool: EMS SQL Manager for MySQL Freeware [http://www.sqlmanager.net/fr/products/mysql/manager/download].
In den folgenden Beispielen lautet das Passwort des Root-Benutzers „root“.
Starten wir MySQL5. Hier tun wir dies über das Windows-Dienstefenster [1]. In [2] läuft das DBMS.
![]() |
Wir starten nun das Tool [SQL Manager Lite for MySQL], mit dem wir das DBMS verwalten werden [3].
![]() |
- In [4] erstellen wir eine neue Datenbank;
- in [5] geben wir den Namen der Datenbank an;
![]() |
- in [5] melden wir uns als root / root an;
- In [6] validieren wir die auszuführende SQL-Anweisung;
![]() |
- In [7] wurde die Datenbank erstellt. Sie muss nun in [EMS Manager] registriert werden. Die Angaben sind korrekt. Klicken Sie auf [OK];
- In [8] stellen wir eine Verbindung her;
- In [9] zeigt [EMS Manager] die Datenbank an, die derzeit leer ist.
Wir werden nun ein VS 2012-Projekt mit dieser Datenbank verbinden.
4.2. Erstellen der Datenbank aus den Entitäten
Wir erstellen das folgende VS 2012-Konsolenprojekt [RdvMedecins-MySQL-01] [1]:
![]() |
- Fügen Sie in [2] über NuGet Verweise auf das Projekt hinzu;
![]() |
- In [3] fügen wir den EF 5-Verweis hinzu;
- in [4] ist sie nun in den Referenzen enthalten;
![]() |
- in [5] wiederholen wir den Vorgang, um [MySQL.Data.Entities] hinzuzufügen, einen ADO.NET-Konnektor für Entity Framework. Um das Paket zu finden, können wir das Suchfeld [6] verwenden;
- in [7] werden zwei Referenzen angezeigt: [MySQL.Data.Entities] und [MySQL.Data], wobei letzteres eine Abhängigkeit des ersteren ist.
Nun erstellen wir das Projekt [RdvMedecins-MySQL-01] auf der Grundlage des Projekts [RdvMedecins-SqlServer-01].
![]() |
- Kopieren Sie in [1] die ausgewählten Elemente;
- Fügen Sie sie in [2] in das Projekt [RdvMedecins-MySQL-01] ein;
- Da es in [3] mehrere Programme mit einer [Main]-Methode gibt, müssen wir das Startprojekt angeben.
An dieser Stelle sollte das Projekt erfolgreich kompiliert werden. Nun ändern wir die Konfigurationsdatei [App.config], die die Datenbankverbindungszeichenfolge und die DbProviderFactory konfiguriert. Sie sieht nun wie folgt aus:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
</entityFramework>
<!-- connecting chain-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- the factory provider -->
<system.data>
<DbProviderFactories>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL"
type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"
/>
</DbProviderFactories>
</system.data>
</configuration>
- Zeile 17: die Verbindungszeichenfolge zur MySQL-Datenbank [rdvmedecins-ef], die wir erstellt haben;
- Zeile 24: Die Version muss mit der der [MySql.Data]-Referenz im Projekt [1] übereinstimmen:
![]() |
Es gibt auch einige Konfigurationen in der Datei [Entities.cs], in der wir die Namen der Tabellen und das Schema angeben, zu dem sie gehören. Dies kann je nach DBMS variieren. Dies ist hier der Fall, wo es kein Schema geben wird. Die Datei [Entities.cs] ändert sich wie folgt:
[Table("MEDECINS")]
public class Medecin : Personne
{...}
[Table("CLIENTS")]
public class Client : Personne
{...}
[Table("CRENEAUX")]
public class Creneau
{...}
[Table("RVS")]
public class Rv
{...}
Führen wir das Programm [CreateDB_01] [2] aus. Wir erhalten die folgende Ausnahme:
Der gleiche Fehler tritt viermal auf (Zeilen 2–5). Der Typ „rowversion“ deutet auf das Feld mit der Annotation [Timestamp] in den Entitäten hin:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Wir beschließen, diese drei Zeilen durch Folgendes zu ersetzen:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
Wir ändern den Spaltentyp von byte[] zu DateTime?. Wir tun dies, weil MySQL über einen [TIMESTAMP]-Typ verfügt, der ein Datum/eine Uhrzeit darstellt, und eine Spalte dieses Typs von MySQL bei jeder Aktualisierung der Zeile automatisch aktualisiert wird. Dies ermöglicht es uns, den gleichzeitigen Zugriff zu verwalten.
Die Annotation [Timestamp] kann nur auf eine Spalte vom Typ byte[] angewendet werden. Wir ersetzen sie durch die Annotation [ConcurrencyCheck]. Beide Annotationen regeln den gleichzeitigen Zugriff. Wir führen diese Änderung für alle vier Entitäten durch und starten die Anwendung anschließend erneut. Daraufhin erhalten wir folgende Fehlermeldung:
Zeile 1 weist auf einen Syntaxfehler im von MySQL ausgeführten SQL-Code hin. Da dieser nicht von uns, sondern vom MySQL-ADO.NET-Anbieter generiert wurde, können wir dieses Problem nicht beheben. Wir können jedoch sehen, dass die Tabellen [1] unten erstellt wurden:
![]() |
- In [2] sehen wir die Struktur der Tabelle [clients] [3].
An der generierten Datenbank sind mehrere Änderungen vorzunehmen:
- Der Datentyp der Spalte [VERSIONING] ist falsch. Er muss auf den MySQL-Typ [TIMESTAMP] gesetzt werden;
- Beachten Sie, dass die Tabelle [rvs] eine Eindeutigkeitsbeschränkung aufweist. Diese wurde bei dieser Generierung nicht erstellt;
- Der SQL Server ADO.NET-Konnektor hat Fremdschlüssel mit der Klausel ON DELETE CASCADE generiert. Der MySQL ADO.NET-Konnektor hat dies nicht getan.
Wie bereits bei SQL Server müssen wir daher die generierte Datenbank anpassen. Wir zeigen nicht, wie die Änderungen vorgenommen werden. Wir stellen lediglich das Skript zum Erstellen der Datenbank bereit:
# SQL Manager Lite for MySQL 5.3.0.2
# ---------------------------------------
# Host : localhost
# Port : 3306
# Database : rdvmedecins-ef
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
SET FOREIGN_KEY_CHECKS=0;
USE `rdvmedecins-ef`;
#
# Structure for the `clients` table :
#
CREATE TABLE `clients` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRENOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`TITRE` VARCHAR(5) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT ''
)ENGINE=InnoDB
AUTO_INCREMENT=96 AVG_ROW_LENGTH=4096 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
#
# Structure for the `medecins` table :
#
CREATE TABLE `medecins` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`NOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`PRENOM` VARCHAR(30) COLLATE utf8_general_ci NOT NULL,
`TITRE` VARCHAR(5) COLLATE utf8_general_ci NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT ''
)ENGINE=InnoDB
AUTO_INCREMENT=56 AVG_ROW_LENGTH=4096 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
#
# Structure for the `creneaux` table :
#
CREATE TABLE `creneaux` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`HDEBUT` INTEGER(11) NOT NULL,
`MDEBUT` INTEGER(11) NOT NULL,
`HFIN` INTEGER(11) NOT NULL,
`MFIN` INTEGER(11) NOT NULL,
`MEDECIN_ID` INTEGER(11) NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT '',
INDEX `MEDECIN_ID` USING BTREE (`MEDECIN_ID`) COMMENT '',
CONSTRAINT `creneaux_ibfk_1` FOREIGN KEY (`MEDECIN_ID`) REFERENCES `medecins` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION
)ENGINE=InnoDB
AUTO_INCREMENT=472 AVG_ROW_LENGTH=455 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
#
# Structure for the `rvs` table :
#
CREATE TABLE `rvs` (
`ID` INTEGER(11) NOT NULL AUTO_INCREMENT,
`JOUR` DATE NOT NULL,
`CRENEAU_ID` INTEGER(11) NOT NULL,
`CLIENT_ID` INTEGER(11) NOT NULL,
`VERSIONING` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY USING BTREE (`ID`) COMMENT '',
UNIQUE INDEX `CRENEAU_ID_JOUR` USING BTREE (`JOUR`, `CRENEAU_ID`) COMMENT '',
INDEX `CRENEAU_ID` USING BTREE (`CRENEAU_ID`) COMMENT '',
INDEX `CLIENT_ID` USING BTREE (`CLIENT_ID`) COMMENT '',
CONSTRAINT `rvs_ibfk_2` FOREIGN KEY (`CLIENT_ID`) REFERENCES `clients` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION,
CONSTRAINT `rvs_ibfk_1` FOREIGN KEY (`CRENEAU_ID`) REFERENCES `creneaux` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION
)ENGINE=InnoDB
AUTO_INCREMENT=28 AVG_ROW_LENGTH=16384 CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'
COMMENT=''
;
- Zeilen 22, 38, 54, 74: Die Primärschlüssel (ID) der Tabellen sind vom Typ AUTO_INCREMENT und werden daher von MySQL generiert;
- Zeilen 26, 42, 60, 78: Die Spalte VERSIONING ist vom Typ TIMESTAMP und wird bei einem INSERT oder UPDATE aktualisiert;
- Zeile 63: Der Fremdschlüssel von der Tabelle [slots] zur Tabelle [doctors] mit der Klausel ON DELETE CASCADE;
- Zeile 80: die Eindeutigkeitsbeschränkung für die Tabelle [rvs];
- Zeile 83: Der Fremdschlüssel von der Tabelle [rvs] zur Tabelle [slots] mit der Klausel ON DELETE CASCADE;
- Zeile 84: der Fremdschlüssel von der Tabelle [rvs] zur Tabelle [clients] mit der Klausel ON DELETE CASCADE;
Das Skript zum Erstellen der Tabellen in der MySQL-Datenbank [rvmedecins-ef] befindet sich im Ordner [RdvMedecins / databases / mysql]. Der Leser kann es laden und ausführen, um die Tabellen zu erstellen.
Sobald dies erledigt ist, können die verschiedenen Programme des Projekts ausgeführt werden. Sie liefern dieselben Ergebnisse wie bei SQL Server, mit Ausnahme des Programms [ModifyDetachedEntities], das abstürzt. Um zu verstehen, warum dies so ist, können wir uns die Ausgabe des Programms [ModifyAttachedEntities] ansehen:
- Zeilen 1–2: ein Client vor dem Speichern des Kontexts;
- Zeilen 3–4: der Client nach dem Speichern. Er verfügt über einen Primärschlüssel, jedoch keinen Wert für das Feld [Versioning], während SQL Server das Feld [Timestamp] der Entität aktualisiert hat.
Sehen wir uns nun den Code für das Programm [ModifyDetachedEntities] an, das abstürzt:
using System;
...
namespace RdvMedecins_01
{
class ModifyDetachedEntities
{
static void Main(string[] args)
{
Client client1;
// empty the current base
Erase();
// add a customer
using (var context = new RdvMedecinsContext())
{
// customer creation
client1 = new Client { Titre = "x", Nom = "x", Prenom = "x" };
// add customer to context
context.Clients.Add(client1);
// save the context
context.SaveChanges();
}
// basic view
Dump("1-----------------------------");
// client1 is not in the context - we modify it
client1.Nom = "y";
// out-of-context entity modification
using (var context = new RdvMedecinsContext())
{
// here we have a new empty context
// we put client1 in the context in a modified state
context.Entry(client1).State = EntityState.Modified;
// save the context
context.SaveChanges();
}
...
}
static void Erase()
{
...
}
static void Dump(string str)
{
...
}
}
}
- Zeile 20: Ein Client wird gespeichert. Er hat nun seinen Primärschlüssel, der jedoch auf seiner Version basiert;
- Zeile 33: Es wird eine Änderung an client1 vorgenommen. Diese schlägt fehl, da die in der Datenbank gespeicherte Version nicht vorhanden ist.
Wir lösen das Problem, indem wir den folgenden Code zwischen Zeile 25 und 26 einfügen:
// retrieve client1 to get its version
using (var context = new RdvMedecinsContext())
{
// customer2 will be in the context
Client client2 = context.Clients.Find(client1.Id);
// set the version of client1 to that of client2
client1.Versioning = client2.Versioning;
}
Nun hat die Entität [client1] dieselbe Version wie in der Datenbank und kann daher zum Aktualisieren der Zeile in der Datenbank verwendet werden.
4.3. Mehrschichtige Architektur auf Basis von EF 5
Kehren wir zu der in Abschnitt 2 beschriebenen Fallstudie zurück.
![]() |
Wir beginnen mit der Erstellung der [DAO]-Datenzugriffsschicht. Dazu erstellen wir das VS 2012-Konsolenprojekt [RdvMedecins-MySQL-02] [1]:
![]() |
- in [2] werden die Referenzen [Common.Logging, EntityFramework, MySql.Data, MySql.Data.Entity, Spring.Core] mithilfe von NuGet hinzugefügt;
- in [3] wird der Ordner [Models] aus dem Projekt [RdvMedecins-MySQL-01] kopiert;
![]() |
- in [4] werden die Ordner [Dao, Exception, Tests] und die Datei [App.config] aus dem Projekt [RdvMedecins-SqlServer-02] kopiert;
- in [5] wurde die Datei [Program.cs] gelöscht;
- in [6] ist das Projekt so konfiguriert, dass das Testprogramm der [DAO]-Schicht ausgeführt wird.
In der Datei [App.config] werden die SQL-Server-Datenbankinformationen durch die der MySQL-Datenbank ersetzt. Diese Informationen finden Sie in der Datei [App.config] des Projekts [RdvMedecins-MySQL-01]:
<!-- connecting chain-->
<connectionStrings>
<add name="monContexte"
connectionString="Server=localhost;Database=rdvmedecins-ef;Uid=root;Pwd=root;"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<!-- the factory provider -->
<system.data>
<DbProviderFactories>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL"
type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"
/>
</DbProviderFactories>
</system.data>
Auch die von Spring verwalteten Objekte ändern sich. Derzeit haben wir:
<!-- spring configuration -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="rdvmedecinsDao" type="RdvMedecins.Dao.Dao,RdvMedecins-SqlServer-02" />
</objects>
</spring>
Zeile 7 verweist auf die Assembly für das Projekt [RdvMedecins-SqlServer-02]. Die Assembly lautet nun [RdvMedecins-MySQL-02].
Damit sind wir bereit, den Test der [DAO]-Schicht auszuführen. Zunächst müssen wir sicherstellen, dass die Datenbank gefüllt ist (mithilfe des Programms [Fill] aus dem Projekt [RdvMedecins-MySQL-01]). Das Testprogramm läuft erfolgreich.
Wir erstellen die DLL des Projekts wie beim Projekt [RdvMedecins-SqlServer-02] und legen alle DLLs des Projekts in einem Ordner [lib] ab, der innerhalb von [RdvMedecins-MySQL-02] erstellt wurde. Diese dienen als Referenzen für das Webprojekt [RdvMedecins-MySQL-03], das wir als Nächstes behandeln werden.
![]() |
Wir sind nun bereit, die [ASP.NET]-Schicht unserer Anwendung zu erstellen:
![]() |
Wir beginnen mit dem Projekt [RdvMedecins-SqlServer-03]. Wir duplizieren den Ordner dieses Projekts in [RdvMedecins-MySQL-03] [1]:
![]() |
- In [2] öffnen wir mit VS 2012 Express for the Web die Lösung im Ordner [RdvMedecins-MySQL-03];
- In [3] ändern wir sowohl den Namen der Lösung als auch den Namen des Projekts;
![]() |
- in [4] die aktuellen Verweise des Projekts;
- in [5] löschen wir sie;
- in [6], um sie durch Verweise auf die DLLs zu ersetzen, die wir gerade in einem [lib]-Ordner innerhalb des Projekts [RdvMedecins-MySQL-02] gespeichert haben.
Nun müssen wir nur noch die Datei [Web.config] ändern. Wir ersetzen ihren aktuellen Inhalt durch den Inhalt der Datei [App.config] aus dem Projekt [RdvMedecins-MySQL-02]. Sobald dies erledigt ist, führen wir das Webprojekt aus. Es funktioniert.
4.4. Fazit
Fassen wir zusammen, was getan wurde, um vom SQL Server-DBMS zum MySQL-DBMS zu wechseln:
- Das Feld, das zur Verwaltung des gleichzeitigen Zugriffs auf Entitäten verwendet wurde, wurde geändert. Die SQL Server-Version lautete:
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
Es ist nun:
[ConcurrencyCheck]
[Column("VERSIONING")]
public DateTime? Versioning { get; set; }
mit MySQL;
- die [Table]-Annotationen, die eine Entität mit einer Tabelle verknüpfen, wurden geändert;
- die Datenbankverbindungszeichenfolge und die [DbProviderFactory] wurden in den Konfigurationsdateien [App.config] und [Web.config] angepasst;
- Nach dem Speichern in der Datenbank verfügte eine SQL Server-Entität sowohl über einen Primärschlüssel als auch über einen Zeitstempel. Bei MySQL verfügte sie nur über einen Primärschlüssel. Dies erforderte eine Codeänderung.
Letztendlich gab es relativ wenige Änderungen, aber wir mussten den Code dennoch überprüfen. Wir wiederholen denselben Prozess für drei weitere DBMS:
- Oracle Database Express Edition 11g Release 2;
- das DBMS PostgreSQL 9.2.1;
- das DBMS Firebird 2.1.
















