6. دراسة حالة مع PostgreSQL 9.2.1
6.1. تثبيت الأدوات
الأدوات التي يجب تثبيتها هي كما يلي:
- نظام إدارة قواعد البيانات (DBMS): [http://www.enterprisedb.com/products-services-training/pgdownload#windows]؛
- أداة إدارة: EMS SQL Manager for PostgreSQL Freeware [http://www.sqlmanager.net/fr/products/postgresql/manager/download].
في الأمثلة التالية، كلمة مرور المستخدم postgres هي postgres.
لنبدأ تشغيل PostgreSQL ثم أداة [SQL Manager Lite for PostgreSQL]، التي سنستخدمها لإدارة نظام إدارة قواعد البيانات.
![]() |
- في [1]، نقوم بتشغيل نظام إدارة قواعد البيانات PostgreSQL من خدمات Windows؛
- في [2]، يتم تشغيل الخدمة؛
نقوم الآن بتشغيل أداة [SQL Manager Lite for MySQL]، التي سنستخدمها لإدارة نظام إدارة قواعد البيانات [3].
![]() |
- في [4]، نقوم بإنشاء قاعدة بيانات جديدة؛
- في [5]، نحدد اسم قاعدة البيانات؛
![]() |
- في [5]، نقوم بتسجيل الدخول باسم postgres / postgres؛
- في [6]، نقدم بعض المعلومات؛
- في [7]، نقوم بالتحقق من صحة عبارة SQL المراد تنفيذها؛
![]() |
- في [8]، تم إنشاء قاعدة البيانات. يجب الآن تسجيلها في [EMS Manager]. المعلومات صحيحة. انقر فوق [موافق]؛
- في [9]، قم بالاتصال بها؛
- في [10]، يعرض [EMS Manager] قاعدة البيانات، وهي فارغة حاليًا. لاحظ أن الجداول ستنتمي إلى مخطط يسمى public [11].
سنقوم الآن بربط مشروع VS 2012 بهذه القاعدة البيانات.
6.2. إنشاء قاعدة البيانات من الكيانات
نبدأ بنسخ مجلد مشروع [RdvMedecins-SqlServer-01] إلى [RdvMedecins-PostgreSQL-01] [1]:
![]() |
- في [2]، في VS 2012، نزيل مشروع [RdvMedecins-SqlServer-01] من الحل؛
![]() |
- في [3]، تمت إزالة المشروع؛
- في [4]، نضيف مشروعًا آخر. هذا المشروع مأخوذ من المجلد [RdvMedecins-PostgreSQL-01] الذي أنشأناه سابقًا؛
![]() |
- في [5]، يُسمى المشروع الذي تم تحميله [RdvMedecins-SqlServer-01]؛
- في [6]، نعيد تسميته إلى [RdvMedecins-PostgreSQL-01]؛
![]() |
- في [7]، نضيف مشروعًا آخر إلى الحل. هذا المشروع مأخوذ من مجلد [RdvMedecins-SqlServer-01] الخاص بالمشروع الذي أزلناه سابقًا من الحل؛
- في [8]، تمت إعادة إضافة مشروع [RdvMedecins-SqlServer-01] إلى الحل.
مشروع [RdvMedecins-PostgreSQL-01] مطابق لمشروع [RdvMedecins-SqlServer-01]. نحتاج إلى إجراء بعض التغييرات. في [App.config]، سنقوم بتعديل سلسلة الاتصال و[DbProviderFactory]، والتي يجب تكييفها مع كل نظام إدارة قواعد البيانات (DBMS).
<!-- 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>
- السطر 3: اسم المستخدم وكلمة المرور؛
- الأسطر 7-9: DbProviderFactory. يشير السطر 8 إلى مكتبة DLL [Npgsql] التي لا نمتلكها. يمكننا الحصول عليها باستخدام NuGet [1]:
![]() |
- في [2]، اكتب الكلمة الرئيسية postgresql في مربع البحث؛
- في [3]، حدد الحزمة [Npgsql]. هذا موصل ADO.NET لـ PostgreSQL؛
![]() |
- في [4]، تمت إضافة مرجعين؛
- في [5]، في [App.config]، يجب تحديد الإصدار الصحيح لملف DLL. يمكنك العثور عليه في خصائصه.
في ملف [Entities.cs]، تحتاج إلى تكييف مخطط الجداول التي سيتم إنشاؤها:
[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
{...}
لقد رأينا سابقًا عند إنشاء قاعدة بيانات PostgreSQL أن الجداول تنتمي إلى مخطط يسمى public.
نقوم بتكوين تنفيذ المشروع:
![]() |
- في [1]، نحدد اسمًا مختلفًا للتجميع الذي سيتم إنشاؤه؛
- في [2]، نحدد أيضًا مساحة أسماء افتراضية مختلفة؛
- في [3]، نحدد البرنامج المراد تنفيذه.
في هذه المرحلة، لا توجد أخطاء في التحويل البرمجي. دعونا نقوم بتشغيل البرنامج [CreateDB_01]. نحصل على الاستثناء التالي:
نتذكر أننا واجهنا نفس الخطأ مع MySQL و Oracle. ويرتبط هذا بنوع حقل Timestamp في الكيانات. نقوم بإجراء نفس التعديل كما في Oracle. في الكيانات، نستبدل الأسطر الثلاثة
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
مع ما يلي:
[ConcurrencyCheck]
[Column("VERSIONING")]
public int? Versioning { get; set; }
نقوم بتغيير نوع العمود من byte[] إلى int?. في نظام إدارة قواعد البيانات (DBMS)، سنستخدم الإجراءات المخزنة لزيادة هذا العدد الصحيح بمقدار واحد في كل مرة يتم فيها إدراج صف أو تعديله.
نجري التغيير أعلاه على الكيانات الأربعة جميعها ثم نعيد تشغيل التطبيق. ثم نحصل على الخطأ التالي:
تشير السطر 1 إلى أن موصل PostgreSQL ADO.NET غير قادر على حذف قاعدة البيانات الحالية. تمامًا كما هو الحال مع Oracle. لذلك، يتعين علينا إنشاء قاعدة البيانات [RDVMEDECINS-EF] يدويًا باستخدام أداة [EMS Manager for PostgreSQL]. لن نصف كل خطوة، بل سنكتفي بذكر أهمها فقط.
ستكون قاعدة بيانات PostgreSQL على النحو التالي:
الجداول
![]() |
- في [1]، ID هو مفتاح أساسي من النوع التسلسلي. هذا النوع في PostgreSQL هو عدد صحيح يتم إنشاؤه تلقائيًا بواسطة نظام إدارة قواعد البيانات (DBMS).
![]() |
![]() |
![]() |
![]() |
تحتوي الجداول المختلفة على المفاتيح الأساسية والمفاتيح الخارجية التي كانت موجودة في هذه الجداول نفسها في الأمثلة السابقة. وتحتوي المفاتيح الخارجية على السمة ON DELETE CASCADE.
التسلسلات
كما هو الحال مع Oracle، قمنا هنا بإنشاء تسلسلات. وهي عبارة عن مولدات للأرقام المتتالية. ويبلغ عددها 5 [1].
![]() |
- في [2]، نرى خصائص التسلسل [CLIENTS_ID_SEQ]. وهو يولد أرقامًا متتالية بزيادات قدرها 1، بدءًا من 1 وصولاً إلى قيمة كبيرة جدًا.
جميع التسلسلات مبنية على نفس النموذج.
- سيُستخدم [CLIENTS_ID_seq] لتوليد المفتاح الأساسي لجدول [CLIENTS]؛
- سيتم استخدام [MEDECINS_ID_seq] لتوليد المفتاح الأساسي لجدول [MEDECINS]؛
- سيتم استخدام [SLOTS_ID_seq] لإنشاء المفتاح الأساسي لجدول [SLOTS]؛
- سيتم استخدام [RVS_ID_seq] لإنشاء المفتاح الأساسي لجدول [RVS]؛
- سيتم استخدام [sequence_versions] لإنشاء القيم لأعمدة [VERSIONING] في جميع الجداول.
المشغلات
المشغل هو إجراء يتم تنفيذه بواسطة نظام إدارة قواعد البيانات (DBMS) قبل أو بعد حدوث حدث (إدراج، تحديث، حذف) في جدول. لدينا 4 منها [1]:
![]() |
دعونا نلقي نظرة على كود DDL لمشغل [CLIENTS_tr]، الذي يملأ عمود [VERSIONING] في جدول [CLIENTS]:
- الأسطر 1-3: قبل كل عملية INSERT أو UPDATE على جدول [CLIENTS]؛
- السطر 4: يتم تنفيذ الإجراء [public.trigger_versions()].
الإجراء [public.trigger_versions()] هو كما يلي:
- السطر 2: يمثل NEW الصف الذي سيتم إدراجه أو تعديله. NEW. "VERSIONING" هو عمود [VERSIONING] في ذلك الصف. يتم تعيين القيمة التالية من مولد الأرقام "sequence_versions" له. وبالتالي، يتغير عمود ["VERSIONING"] مع كل عملية INSERT أو UPDATE يتم إجراؤها على جدول [CLIENTS].
تعمل المشغلات [MEDECINS_tr، CRENEAUX_tr، RVS_tr] بنفس الطريقة. تستمد الأعمدة الأربعة ["VERSIONING"] قيمها من نفس التسلسل.
تم وضع البرنامج النصي لإنشاء الجداول في قاعدة بيانات PostgreSQL [RDVMEDECINS-EF] في المجلد [RdvMedecins / databases / postgreSQL]. يمكن للقارئ تحميله وتشغيله لإنشاء الجداول.
بمجرد الانتهاء من ذلك، يمكن تشغيل البرامج المختلفة في المشروع. تنتج هذه البرامج نفس النتائج كما هو الحال مع SQL Server، باستثناء برنامج [ModifyDetachedEntities]، الذي يتعطل لنفس السبب الذي تسبب في تعطله مع Oracle. يتم حل المشكلة بنفس الطريقة. ما عليك سوى نسخ برنامج [ModifyDetachedEntities] من مشروع [RdvMedecins-Oracle-01] إلى مشروع [RdvMedecins-PostgreSQL-01].
يتعطل برنامج [LazyEagerLoading] مع الاستثناء التالي:
الرمز غير الصحيح هو كما يلي:
using (var context = new RdvMedecinsContext())
{
// crenel n° 0
creneau = context.Creneaux.Include("Medecin").Single<Creneau>(c => c.Id == idCreneau);
Console.WriteLine(creneau.ShortIdentity());
}
السطر 1 من الاستثناء: يشير الخطأ المبلغ عنه إلى وجود عملية ربط لأن LEFT هي كلمة رئيسية للربط. نظرًا لأن السطر 4 من الكود أعلاه يطلب التحميل الفوري لتبعية [Doctor] لكيان [Appointment]، فقد أجرى EF عملية ربط بين الجدولين [APPOINTMENTS] و[DOCTORS]. ومع ذلك، يبدو أن موصل ADO.NET قد أنشأ عبارة SQL غير صحيحة. نعيد كتابة الكود على النحو التالي:
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;
}
- السطر 4: نسترد الفتحة بدون ربط؛
- السطر 8: نسترد التبعية المفقودة.
إنه يعمل. مرة أخرى، نرى أن تغيير نظام إدارة قواعد البيانات (DBMS) يؤثر على الكود. في الواقع، ليست مشكلة نظام إدارة قواعد البيانات (DBMS) هي المشكلة هنا، بل موصل ADO.NET الخاص به.
6.3. بنية متعددة الطبقات تستند إلى EF 5
نعود إلى دراسة الحالة الموضحة في الفقرة 2.
![]() |
سنبدأ ببناء طبقة الوصول إلى البيانات [DAO]. للقيام بذلك، نقوم بنسخ مشروع وحدة التحكم في VS 2012 [RdvMedecins-SqlServer-02] إلى [RdvMedecins-PostgreSQL-02] [1]:
![]() |
- في [2]، احذف المشروع [RdvMedecins-SqlServer-02]؛
![]() |
- في [3]، أضف مشروعًا موجودًا إلى الحل. خذ المشروع من المجلد [RdvMedecins-PostgreSQL-02] الذي تم إنشاؤه للتو؛
- في [4]، يحمل المشروع الجديد نفس اسم المشروع الذي تم حذفه. سنقوم بتغيير اسمه؛
![]() |
- في [5]، قمنا بتغيير اسم المشروع؛
- في [6]، نقوم بتعديل بعض خصائصه، مثل اسم التجميع هنا؛
- في [7]، تم حذف مجلد [Models] واستبداله بمجلد [Models] من مشروع [RdvMedecins-PostgreSQL-01]. وذلك لأن كلا المشروعين يشتركان في نفس النماذج.
![]() |
- في [8]، المراجع الحالية للمشروع؛
- في [9]، تمت إضافة موصل PostgreSQL ADO.NET باستخدام أداة NuGet.
في ملف [App.config]، استبدل معلومات قاعدة بيانات SQL Server بمعلومات قاعدة بيانات PostgreSQL. يمكن العثور على هذه المعلومات في ملف [App.config] الخاص بمشروع [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>
تتغير أيضًا الكائنات التي يديرها Spring. لدينا حاليًا:
<!-- 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>
يشير السطر 7 إلى التجميع الخاص بمشروع [RdvMedecins-SqlServer-02]. أصبح التجميع الآن [RdvMedecins-PostgreSQL-02].
وبعد الانتهاء من ذلك، نكون جاهزين لتشغيل اختبار طبقة [DAO]. أولاً، يجب أن نتأكد من أن قاعدة البيانات مملوءة (باستخدام برنامج [Fill] من مشروع [RdvMedecins-PostgreSQL-01]). يتعطل برنامج الاختبار مع الاستثناء التالي:
السطر 13: تشير الرسالة إلى أن الخطأ حدث في طريقة [GetCreneauxMedecin] في طبقة [DAO]. هذه الطريقة هي كما يلي:
// 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);
}
}
السطر 11: نلاحظ كلمة Include، التي كانت تتسبب سابقًا في تعطل البرنامج. يمكن استبدال الكود السابق بما يلي:
// 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);
}
}
يبدو الكود الجديد أكثر اتساقًا من القديم. على أي حال، نجح برنامج الاختبار هذه المرة.
نقوم بإنشاء ملف DLL الخاص بالمشروع كما فعلنا مع مشروع [RdvMedecins-SqlServer-02]، ونجمع جميع ملفات DLL الخاصة بالمشروع في مجلد [lib] تم إنشاؤه داخل [RdvMedecins-PostgreSQL-02]. وستكون هذه هي المراجع لمشروع الويب [RdvMedecins-PostgreSQL-03] الذي سيأتي بعد ذلك.
![]() |
نحن الآن جاهزون لإنشاء طبقة [ASP.NET] لتطبيقنا:
![]() |
سنبدأ بمشروع [RdvMedecins-SqlServer-03]. نقوم بنسخ مجلد هذا المشروع إلى [RdvMedecins-PostgreSQL-03] [1]:
![]() |
- في [2]، باستخدام VS 2012 Express for the Web، نفتح الحل في مجلد [RdvMedecins-PostgreSQL-03]؛
- في [3]، نقوم بتغيير اسم الحل واسم المشروع؛
![]() |
- في [4]، المراجع الحالية للمشروع؛
- في [5]، نقوم بحذفها؛
- في [6]، لاستبدالها بمراجع إلى ملفات DLL التي قمنا بتخزينها للتو في مجلد [lib] في مشروع [RdvMedecins-PostgreSQL-02].
كل ما تبقى هو تعديل ملف [Web.config]. نستبدل محتواه الحالي بمحتوى ملف [App.config] من مشروع [RdvMedecins-PostgreSQL-02]. بمجرد الانتهاء من ذلك، نقوم بتشغيل مشروع الويب. إنه يعمل. يجب ألا ننسى ملء قاعدة البيانات قبل تشغيل تطبيق الويب.


























