6. Fallstudie mit PostgreSQL 9.2.1
6.1. Installation der Tools
Folgende Tools müssen installiert werden:
- das DBMS: [http://www.enterprisedb.com/products-services-training/pgdownload#windows];
- ein Verwaltungstool: EMS SQL Manager for PostgreSQL Freeware [http://www.sqlmanager.net/fr/products/postgresql/manager/download].
In den folgenden Beispielen hat der Benutzer postgres das Passwort postgres.
Starten wir PostgreSQL und anschließend das Tool [SQL Manager Lite for PostgreSQL], das wir zur Verwaltung des DBMS verwenden werden.
![]() |
- In [1] starten wir das PostgreSQL-DBMS über die Windows-Dienste;
- In [2] wird der Dienst gestartet;
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 postgres / postgres an;
- In [6] liefern wir einige Informationen;
- In [7] validieren wir die auszuführende SQL-Anweisung;
![]() |
- In [8] wurde die Datenbank erstellt. Sie muss nun in [EMS Manager] registriert werden. Die Angaben sind korrekt. Klicken Sie auf [OK];
- Stellen Sie in [9] eine Verbindung her;
- In [10] zeigt [EMS Manager] die Datenbank an, die derzeit leer ist. Beachten Sie, dass die Tabellen zu einem Schema namens public [11] gehören werden.
Wir werden nun ein VS 2012-Projekt mit dieser Datenbank verbinden.
6.2. Erstellen der Datenbank aus den Entitäten
Zunächst duplizieren wir den Projektordner [RdvMedecins-SqlServer-01] in [RdvMedecins-PostgreSQL-01] [1]:
![]() |
- In [2] entfernen wir in VS 2012 das Projekt [RdvMedecins-SqlServer-01] aus der Lösung;
![]() |
- in [3] wurde das Projekt entfernt;
- in [4] fügen wir ein weiteres hinzu. Dieses stammt aus dem Ordner [RdvMedecins-PostgreSQL-01], den wir zuvor erstellt haben;
![]() |
- in [5] heißt das geladene Projekt [RdvMedecins-SqlServer-01];
- in [6] benennen wir es in [RdvMedecins-PostgreSQL-01] um;
![]() |
- In [7] fügen wir der Lösung ein weiteres Projekt hinzu. Dieses stammt aus dem Ordner [RdvMedecins-SqlServer-01] des Projekts, das wir zuvor aus der Lösung entfernt haben;
- In [8] wurde das Projekt [RdvMedecins-SqlServer-01] wieder zur Lösung hinzugefügt.
Das Projekt [RdvMedecins-PostgreSQL-01] ist identisch mit dem Projekt [RdvMedecins-SqlServer-01]. Wir müssen einige Änderungen vornehmen. In [App.config] werden wir die Verbindungszeichenfolge und die [DbProviderFactory] anpassen, die jeweils an das jeweilige DBMS angepasst werden müssen.
<!-- connection chain on base -->
<connectionStrings>
<add name="monContexte" connectionString="Server=127.0.0.1;Port=5432;Database=rdvmedecins-ef;User Id=postgres;Password=postgres;" providerName="Npgsql" />
</connectionStrings>
<!-- the factory provider -->
<system.data>
<DbProviderFactories>
<add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql Server" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.11.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" />
</DbProviderFactories>
</system.data>
- Zeile 3: Benutzername und Passwort;
- Zeilen 7–9: die DbProviderFactory. Zeile 8 verweist auf eine DLL [Npgsql], die wir nicht haben. Wir können sie über NuGet [1] beziehen:
![]() |
- Geben Sie in [2] das Stichwort „postgresql“ in das Suchfeld ein;
- Wählen Sie unter [3] das Paket [Npgsql] aus. Dies ist ein ADO.NET-Konnektor für PostgreSQL;
![]() |
- In [4] wurden zwei Verweise hinzugefügt;
- in [5], in [App.config], müssen Sie die richtige Version der DLL angeben. Diese finden Sie in den Eigenschaften der Datei.
In der Datei [Entities.cs] müssen Sie das Schema der zu generierenden Tabellen anpassen:
[Table("MEDECINS", Schema = "public")]
public class Medecin : Personne
{...}
[Table("CLIENTS", Schema = "public")]
public class Client : Personne
{...}
[Table("CRENEAUX", Schema = "public")]
public class Creneau
{...}
[Table("RVS", Schema = "public")]
public class Rv
{...}
Wir haben zuvor beim Erstellen einer PostgreSQL-Datenbank gesehen, dass die Tabellen zu einem Schema namens „public“ gehörten.
Wir konfigurieren die Ausführung des Projekts:
![]() |
- In [1] geben wir der zu generierenden Assembly einen anderen Namen;
- in [2] geben wir zudem einen anderen Standard-Namespace an;
- in [3] geben wir das auszuführende Programm an.
Zu diesem Zeitpunkt gibt es keine Kompilierungsfehler. Führen wir das Programm [CreateDB_01] aus. Wir erhalten die folgende Ausnahme:
Wir erinnern uns, dass wir denselben Fehler bereits bei MySQL und Oracle hatten. Dies hängt mit dem Typ des Timestamp-Feldes in den Entitäten zusammen. Wir nehmen dieselbe Änderung vor wie bei Oracle. In den Entitäten ersetzen wir die drei Zeilen
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
mit folgendem Inhalt:
[ConcurrencyCheck]
[Column("VERSIONING")]
public int? Versioning { get; set; }
Wir ändern den Spaltentyp von byte[] zu int?. Im DBMS verwenden wir gespeicherte Prozeduren, um diese Ganzzahl jedes Mal um eins zu erhöhen, wenn eine Zeile eingefügt oder geändert wird.
Wir nehmen die oben genannte Änderung an allen vier Entitäten vor und führen die Anwendung anschließend erneut aus. Daraufhin erhalten wir die folgende Fehlermeldung:
Zeile 1 weist darauf hin, dass der PostgreSQL-ADO.NET-Konnektor die vorhandene Datenbank nicht löschen kann. Genau wie bei Oracle. Wir müssen daher die Datenbank [RDVMEDECINS-EF] manuell mit dem Tool [EMS Manager for PostgreSQL] erstellen. Wir werden nicht jeden Schritt beschreiben, sondern nur die wichtigsten.
Die PostgreSQL-Datenbank sieht wie folgt aus:
Die Tabellen
![]() |
- In [1] ist ID ein Primärschlüssel vom Typ serial. Dieser PostgreSQL-Typ ist eine vom DBMS automatisch generierte Ganzzahl.
![]() |
![]() |
![]() |
![]() |
Die verschiedenen Tabellen enthalten die Primär- und Fremdschlüssel, die diese Tabellen bereits in den vorherigen Beispielen hatten. Die Fremdschlüssel verfügen über das Attribut ON DELETE CASCADE.
Sequenzen
Wie bei Oracle haben wir auch hier Sequenzen angelegt. Dabei handelt es sich um Generatoren für fortlaufende Zahlen. Es gibt insgesamt 5 davon [1].
![]() |
- In [2] sehen wir die Eigenschaften der Sequenz [CLIENTS_ID_SEQ]. Sie generiert fortlaufende Zahlen in Schritten von 1, beginnend bei 1 bis zu einem sehr großen Wert.
Alle Sequenzen basieren auf demselben Modell.
- [CLIENTS_ID_seq] wird verwendet, um den Primärschlüssel für die Tabelle [CLIENTS] zu generieren;
- [MEDECINS_ID_seq] wird zur Generierung des Primärschlüssels für die Tabelle [MEDECINS] verwendet;
- [SLOTS_ID_seq] wird zur Generierung des Primärschlüssels für die Tabelle [SLOTS] verwendet;
- [RVS_ID_seq] wird zur Generierung des Primärschlüssels für die Tabelle [RVS] verwendet;
- [sequence_versions] wird verwendet, um die Werte für die [VERSIONING]-Spalten in allen Tabellen zu generieren.
Trigger
Ein Trigger ist eine Prozedur, die vom DBMS vor oder nach einem Ereignis (Insert, Update, Delete) in einer Tabelle ausgeführt wird. Wir haben 4 davon [1]:
![]() |
Sehen wir uns den DDL-Code für den Trigger [CLIENTS_tr] an, der die Spalte [VERSIONING] der Tabelle [CLIENTS] füllt:
- Zeilen 1–3: vor jeder INSERT- oder UPDATE-Operation in der Tabelle [CLIENTS];
- Zeile 4: Die Prozedur [public.trigger_versions()] wird ausgeführt.
Die Prozedur [public.trigger_versions()] lautet wie folgt:
- Zeile 2: NEW steht für die Zeile, die gerade eingefügt oder geändert werden soll. NEW. „VERSIONING“ ist die Spalte [VERSIONING] dieser Zeile. Ihr wird der nächste Wert aus dem Zahlengenerator „sequence_versions“ zugewiesen. Somit ändert sich die Spalte [„VERSIONING“] bei jedem INSERT oder UPDATE, das an der Tabelle [CLIENTS] durchgeführt wird.
Die Trigger [MEDECINS_tr, CRENEAUX_tr, RVS_tr] funktionieren auf die gleiche Weise. Die vier ["VERSIONING"]-Spalten leiten ihre Werte aus derselben Sequenz ab.
Das Skript zum Erstellen der Tabellen in der PostgreSQL-Datenbank [RDVMEDECINS-EF] wurde im Ordner [RdvMedecins / databases / postgreSQL] abgelegt. Der Leser kann es laden und ausführen, um die Tabellen zu erstellen.
Sobald dies geschehen ist, können die verschiedenen Programme im Projekt ausgeführt werden. Sie liefern dieselben Ergebnisse wie bei SQL Server, mit Ausnahme des Programms [ModifyDetachedEntities], das aus demselben Grund abstürzt, aus dem es auch bei Oracle abgestürzt ist. Das Problem wird auf dieselbe Weise gelöst. Kopieren Sie einfach das Programm [ModifyDetachedEntities] aus dem Projekt [RdvMedecins-Oracle-01] in das Projekt [RdvMedecins-PostgreSQL-01].
Das Programm [LazyEagerLoading] stürzt mit der folgenden Ausnahme ab:
Der fehlerhafte Code lautet wie folgt:
using (var context = new RdvMedecinsContext())
{
// crenel n° 0
creneau = context.Creneaux.Include("Medecin").Single<Creneau>(c => c.Id == idCreneau);
Console.WriteLine(creneau.ShortIdentity());
}
Zeile 1 der Ausnahme: Der gemeldete Fehler deutet auf eine Verknüpfung hin, da LEFT ein Verknüpfungsschlüsselwort ist. Da Zeile 4 des obigen Codes das sofortige Laden der Abhängigkeit [Doctor] für eine [Appointment]-Entität anfordert, führte EF eine Verknüpfung zwischen den Tabellen [APPOINTMENTS] und [DOCTORS] durch. Es scheint jedoch, dass der ADO.NET-Konnektor eine falsche SQL-Anweisung generiert hat. Wir schreiben den Code wie folgt um:
using (var context = new RdvMedecinsContext())
{
// crenel n° 0
creneau = context.Creneaux.Find(idCreneau);
Console.WriteLine(creneau.ShortIdentity());
// force the loading of the associated doctor
// it's possible because we're still in an open context
Medecin medecin = creneau.Medecin;
}
- Zeile 4: Wir rufen den Slot ohne Join ab;
- Zeile 8: Wir rufen die fehlende Abhängigkeit ab.
Es funktioniert. Wieder einmal sehen wir, dass ein Wechsel des DBMS Auswirkungen auf den Code hat. Tatsächlich ist hier nicht das DBMS das Problem, sondern dessen ADO.NET-Konnektor.
6.3. Mehrschichtige Architektur auf Basis von EF 5
Wir kehren zu unserer in Absatz 2 beschriebenen Fallstudie zurück.
![]() |
Zunächst erstellen wir die [DAO]-Datenzugriffsschicht. Dazu duplizieren wir das VS 2012-Konsolenprojekt [RdvMedecins-SqlServer-02] in [RdvMedecins-PostgreSQL-02] [1]:
![]() |
- Löschen Sie in [2] das Projekt [RdvMedecins-SqlServer-02];
![]() |
- Fügen Sie in [3] ein vorhandenes Projekt zur Lösung hinzu. Wählen Sie es aus dem soeben erstellten Ordner [RdvMedecins-PostgreSQL-02] aus;
- In [4] hat das neue Projekt denselben Namen wie das gelöschte. Wir werden seinen Namen ändern;
![]() |
- In [5] haben wir den Projektnamen geändert;
- In [6] ändern wir einige seiner Eigenschaften, wie hier den Assemblierungsnamen;
- In [7] wird der Ordner [Models] gelöscht und durch den Ordner [Models] aus dem Projekt [RdvMedecins-PostgreSQL-01] ersetzt. Dies liegt daran, dass beide Projekte dieselben Modelle verwenden.
![]() |
- in [8] die aktuellen Verweise des Projekts;
- in [9] wurde der PostgreSQL-ADO.NET-Konnektor mithilfe des NuGet-Tools hinzugefügt.
Ersetzen Sie in der Datei [App.config] die SQL-Server-Datenbankinformationen durch die der PostgreSQL-Datenbank. Diese Informationen finden Sie in der Datei [App.config] des Projekts [RdvMedecins-PostgreSQL-01]:
<!-- connection chain on base -->
<connectionStrings>
<add name="monContexte" connectionString="Server=127.0.0.1;Port=5432;Database=rdvmedecins-ef;User Id=postgres;Password=postgres;" providerName="Npgsql" />
</connectionStrings>
<!-- the factory provider -->
<system.data>
<DbProviderFactories>
<add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql Server" type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.11.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" />
</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-PostgreSQL-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-PostgreSQL-01]). Das Testprogramm stürzt mit der folgenden Ausnahme ab:
Zeile 13: Die Meldung weist darauf hin, dass der Fehler in der Methode [GetCreneauxMedecin] der [DAO]-Schicht aufgetreten ist. Diese Methode lautet wie folgt:
// list of time slots for a given doctor
public List<Creneau> GetCreneauxMedecin(int idMedecin)
{
// list of slots
try
{
// opening persistence context
using (var context = new RdvMedecinsContext())
{
// we get the doctor back with his slots
Medecin medecin = context.Medecins.Include("Creneaux").Single(m => m.Id == idMedecin);
// returns a list of the doctor's slots
return medecin.Creneaux.ToList<Creneau>();
}
}
catch (Exception ex)
{
throw new RdvMedecinsException(3, "GetCreneauxMedecin", ex);
}
}
Zeile 11: Wir erkennen das Schlüsselwort „Include“, das zuvor einen Programmabsturz verursacht hat. Der vorherige Code kann durch Folgendes ersetzt werden:
// list of time slots for a given doctor
public List<Creneau> GetCreneauxMedecin(int idMedecin)
{
// list of slots
try
{
// opening persistence context
using (var context = new RdvMedecinsContext())
{
// returns a list of the doctor's slots
return context.Creneaux.Where(c => c.MedecinId == idMedecin).ToList<Creneau>();
}
}
catch (Exception ex)
{
throw new RdvMedecinsException(3, "GetCreneauxMedecin", ex);
}
}
Der neue Code wirkt sogar noch konsistenter als der alte. Auf jeden Fall besteht das Testprogramm diesmal.
Wir erstellen die DLL des Projekts wie bereits beim Projekt [RdvMedecins-SqlServer-02] und sammeln alle DLLs des Projekts in einem Ordner [lib], der innerhalb von [RdvMedecins-PostgreSQL-02] angelegt wird. Diese dienen als Referenzen für das nachfolgende Webprojekt [RdvMedecins-PostgreSQL-03].
![]() |
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-PostgreSQL-03] [1]:
![]() |
- In [2] öffnen wir mit VS 2012 Express for the Web die Lösung im Ordner [RdvMedecins-PostgreSQL-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 im Projekt [RdvMedecins-PostgreSQL-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-PostgreSQL-02]. Sobald dies erledigt ist, führen wir das Webprojekt aus. Es funktioniert. Wir dürfen nicht vergessen, die Datenbank zu füllen, bevor wir die Webanwendung ausführen.


























