20. تطبيق الويب MVC في بنية ثلاثية الطبقات – المثال 6، SQL Server Express
20.1. قاعدة البيانات SQL Server Express
في هذا الإصدار، سنقوم بتثبيت قائمة الأشخاص في جدول قاعدة بيانات SQL Server Express 2005 المتاح على الرابط [http://msdn.microsoft.com/vstudio/express/sql/]. فيما يلي، تأتي لقطات الشاشة من عميل EMS Manager Lite لـ SQL Server Express [http://www.sqlmanager.net/fr/products/mssql/manager]، وهو عميل إدارة مجاني لـ SGBD SQL Server Express.
تسمى قاعدة البيانات [dbpersonnes]. وهي تحتوي على جدول [PERSONNES]:

ستحتوي الجدولة [PERSONNES] على قائمة بالأشخاص الذين تديرهم تطبيق الويب. وقد تم إنشاؤها باستخدام الأوامر التالية SQL:
- السطر 2: المفتاح الأساسي [ID] هو من النوع الصحيح. يشير السمة IDENTITY إلى أنه في حالة إدراج سطر بدون قيمة للعمود ID في الجدول، سيقوم SQL Express بنفسه بإنشاء عدد صحيح لهذا العمود. في IDENTITY(1, 1)، المعلمة الأولى هي أول قيمة ممكنة للمفتاح الأساسي، والثانية هي الزيادة المستخدمة في إنشاء الأرقام.
قد تحتوي الجدول [PERSONNES] على المحتوى التالي:

نعلم أنه عند إدراج كائن [Personne] بواسطة طبقتنا [dao]، يكون الحقل [id] لهذا الكائن مساوياً لـ -1 قبل الإدراج ويكون له قيمة مختلفة عن -1 بعد ذلك، وتكون هذه القيمة هي المفتاح الأساسي المخصص للسطر الجديد الذي تم إدراجه في الجدول [PERSONNES]. لنرى من خلال مثال كيف يمكننا معرفة هذه القيمة.
![]() |
![]() |
الطلب SQL
معرفة آخر قيمة تم إدخالها في الحقل ID في الجدول. ويجب إصدارها بعد الإدخال. وهذا يختلف عن SGBD و [Firebird] و [Postgres] حيث كنا نطلب قيمة المفتاح الأساسي للشخص المضاف قبل الإدراج، ولكن هذا مشابه لتوليد المفتاح الأساسي في SGBD و MySQL. سنستخدمه في الملف [personnes-sqlexpress.xml] الذي يجمع الأوامر SQL التي تم إصدارها على قاعدة البيانات.
20.2. مشروع Eclipse للطبقات [dao] و [service]
لتطوير الطبقات [dao] و [service] لتطبيقنا باستخدام قاعدة البيانات [SQL Server Express]، سنستخدم مشروع Eclipse [mvc-personnes-06] التالي:

المشروع هو مشروع Java بسيط، وليس مشروع ويب Tomcat.
مجلد [src]
يحتوي هذا الملف على أكواد المصدر للطبقات [dao] و [service]:

قد تكون جميع الملفات التي تحتوي على [sqlexpress] في اسمها قد خضعت أو لم تخضع لتعديل مقارنة بإصدارات Firebird و Postgres و MySQL. فيما يلي، نصف فقط تلك التي تم تعديلها.
المجلد [database]
يحتوي هذا الملف على البرنامج النصي لإنشاء قاعدة بيانات SQL Express للأشخاص:
![]()
المجلد [lib]
يحتوي هذا الملف على الأرشيفات اللازمة للتطبيق:
![]() |
تجدر الإشارة إلى وجود برنامج التشغيل jdbc [sqljdbc.jar] من SGBD [Sql Server Express]. جميع هذه الملفات هي جزء من Classpath لمشروع Eclipse.
20.3. الطبقة [dao]
الطبقة [dao] هي التالية:

نقدم فقط التغييرات التي طرأت مقارنة بالإصدار [Firebird].
ملف التعيين [personne-sqlexpress.xml] هو التالي:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap
PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN"
"http://www.ibatis.com/dtd/sql-map-2.dtd">
<sqlMap>
<!-- اسم مستعار لفئة [Personne] -->
<typeAlias alias="Personne.classe"
type="istia.st.mvc.personnes.entites.Personne"/>
<!-- جدول التعيين [PERSONNES] - الكائن [Personne] -->
<resultMap id="Personne.map"
class="istia.st.mvc.personnes.entites.Personne">
<result property="id" column="ID" />
<result property="version" column="VERSION" />
<result property="nom" column="NOM"/>
<result property="prenom" column="PRENOM"/>
<result property="dateNaissance" column="DATENAISSANCE"/>
<result property="marie" column="MARIE"/>
<result property="nbEnfants" column="NBENFANTS"/>
</resultMap>
<!-- قائمة بجميع الأشخاص -->
<select id="Personne.getAll" resultMap="Personne.map" > select ID, VERSION, NOM,
PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES</select>
<!-- الحصول على شخص معين -->
<select id="Personne.getOne" resultMap="Personne.map" >select ID, VERSION, NOM,
PRENOM, DATENAISSANCE, MARIE, NBENFANTS FROM PERSONNES WHERE ID=#القيمة#</select>
<!-- إضافة شخص -->
<insert id="Personne.insertOne" parameterClass="Personne.classe">
insert into
PERSONNES(VERSION, NOM, PRENOM, DATENAISSANCE, MARIE, NBENFANTS)
VALUES(#الإصدار#، #اللقب#، #الاسم الأول#، #dateNaissance#، #ماري#،
#nbEnfants#)
<selectKey keyProperty="id">
select @@IDENTITY as value
</selectKey>
</insert>
<!-- تحديث شخص -->
<update id="Personne.updateOne" parameterClass="Personne.classe"> update
PERSONNES set VERSION=#الإصدار#+1، NOM=#اللقب#، PRENOM=#الاسم الأول#، DATENAISSANCE=#dateNaissance#,
MARIE=#marie#، NBENFANTS=#nbEnfants# WHERE ID=#id# و
VERSION=#version#</update>
<!-- حذف شخص -->
<delete id="Personne.deleteOne" parameterClass="int"> delete FROM PERSONNES WHERE
ID=#value# </delete>
<!-- الحصول على قيمة المفتاح الأساسي [id] لآخر شخص تم إدراجه -->
<select id="Personne.getNextId" resultClass="int">select
LAST_INSERT_ID()</select>
</sqlMap>
وهو نفس محتوى [personnes-firebird.xml] باستثناء التفاصيل التالية:
- تغير ترتيب SQL " Personne.insertOne " في الأسطر 29-37:
- يتم تنفيذ أمر الإدراج SQL قبل الأمر SELECT الذي سيسمح باسترداد قيمة المفتاح الأساسي للسطر الذي تم إدراجه
- أمر الإدراج SQL ليس له قيمة في العمود ID من الجدول [PERSONNES]
وهذا يعكس مثال الإدراج الذي علقنا عليه في الفقرة 20.1. وتجدر الإشارة إلى أننا نجد هنا مشكلة الإدراجات المتزامنة بواسطة خيوط مختلفة الموصوفة لـ MySQL في الفقرة 19.3.
فئة التنفيذ [DaoImplCommon] للطبقة [dao] هي نفس فئة الإصدارات الثلاثة السابقة.
تم تكييف تكوين الطبقة [dao] مع SGBD [SQL Express]. وبالتالي، فإن ملف التكوين [spring-config-test-dao-sqlexpress.xml] هو التالي:
<?xml version="1.0" encoding="ISO_8859-1"?>
<!DOCTYPE beans SYSTEM "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- مصدر البيانات DBCP -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>com.microsoft.sqlserver.jdbc.SQLServerDriver</value>
</property>
<property name="url">
<value>jdbc:sqlserver://localhost\\SQLEXPRESS:4000;databaseName=dbpersonnes</value>
</property>
<property name="username">
<value>sa</value>
</property>
<property name="password">
<value>msde</value>
</property>
</bean>
<!-- SqlMapCllient -->
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource">
<ref local="dataSource"/>
</property>
<property name="configLocation">
<value>classpath:sql-map-config-sqlexpress.xml</value>
</property>
</bean>
<!-- فئة الوصول إلى الطبقة [dao] -->
<bean id="dao" class="istia.st.mvc.personnes.dao.DaoImplCommon">
<property name="sqlMapClient">
<ref local="sqlMapClient"/>
</property>
</bean>
</beans>
- الأسطر 5-19: يشير bean [dataSource] الآن إلى قاعدة البيانات [SQL Express] [dbpersonnes] التي يكون مسؤولها هو [sa] بكلمة مرور [msde]. سيقوم القارئ بتعديل هذا التكوين وفقًا لبيئته الخاصة.
- السطر 31: الفئة [DaoImplCommon] هي فئة تنفيذ الطبقة [dao]
السطر 11 يستحق بعض التوضيح:
- //localhost: يشير إلى أن خادم SQL Express موجود على نفس الجهاز الذي يعمل عليه تطبيق Java الخاص بنا
- \\SQLEXPRESS: هو اسم مثيل لخادم SQL. يبدو أنه يمكن تشغيل عدة مثيلات في نفس الوقت. لذلك يبدو من المنطقي تسمية المثيل الذي نتعامل معه. يمكن الحصول على هذا الاسم من خلال [SQL Server Configuration Manager] الذي يتم تثبيته عادةً في نفس الوقت مع SQL Express:


- 4000: منفذ الاستماع لـ SQL Express. وهذا يعتمد على تكوين الخادم. بشكل افتراضي، يعمل مع منافذ ديناميكية، وبالتالي غير معروفة مسبقًا. لذلك لا يتم تحديد منفذ في عنوان URL JDBC. هنا، عملنا مع منفذ ثابت، وهو المنفذ 4000. يتم الحصول عليه من خلال التكوين:
![]() |
- يحدد السمة dataBaseName قاعدة البيانات التي نريد العمل بها. وهي القاعدة التي تم إنشاؤها باستخدام العميل EMS:

بعد إجراء هذه التعديلات، يمكننا الانتقال إلى الاختبارات.
20.4. اختبارات الطبقات [dao] و [service]
اختبارات الطبقات [dao] و [service] هي نفسها التي أجريت على الإصدار [Firebird]. وفيما يلي النتائج التي تم الحصول عليها:
![]() |
يلاحظ أن الاختبارات قد نجحت مع تطبيق [DaoImplCommon]. لن نضطر إلى اشتقاق هذه الفئة كما كان ضروريًا مع SGBD و [Firebird].
20.5. اختبارات تطبيق [web]
لاختبار تطبيق الويب باستخدام SGBD و [SQL Server Express]، نقوم بإنشاء مشروع Eclipse [mvc-personnes-06B] بطريقة مماثلة لتلك المستخدمة في إنشاء مشاريع الويب السابقة.
نقوم بنشر مشروع الويب [mvc-personnes-05B] داخل Tomcat:
![]() | ![]() |
يتم تشغيل خادم Express SGBD SQL. ويكون محتوى الجدول [PERSONNES] كما يلي:

يتم تشغيل Tomcat بدوره. باستخدام متصفح، نطلب عنوان URL [http://localhost:8080/mvc-personnes-06B]:

نضيف شخصًا جديدًا عبر الرابط [Ajout]:
![]() | ![]() |
نتحقق من الإضافة في قاعدة البيانات:

يُطلب من القارئ إجراء اختبارات أخرى [modification, suppression].








