Skip to content

7. الوصول إلى قواعد البيانات

7.1. معلومات عامة

توجد العديد من قواعد البيانات الخاصة بمنصات ويندوز. وللوصول إليها، تمر التطبيقات عبر برامج تُسمى برامج التشغيل (drivers).

في الرسم التخطيطي أعلاه، يقدم برنامج التشغيل واجهتين:

  • الواجهة I1 التي تُعرض على التطبيق
  • الواجهة I2 الموجهة إلى قاعدة البيانات

ولتجنب الحاجة إلى إعادة كتابة تطبيق مكتوب لقاعدة بيانات B1 في حالة الترحيل إلى قاعدة بيانات مختلفة مثل B2، تم بذل جهد لتوحيد واجهة I1. في حالة استخدام قواعد البيانات التي تعتمد على برامج تشغيل «معيارية»، سيتم توفير قاعدة البيانات B1 مع برنامج تشغيل P1، وقاعدة البيانات B2 مع برنامج تشغيل P2، وستكون واجهة I1 لهذين البرنامجين متطابقة. وبالتالي لن يكون هناك داعٍ لإعادة كتابة التطبيق. وبذلك يمكن، على سبيل المثال، ترحيل قاعدة بيانات ACCESS إلى قاعدة بيانات MySQL دون تغيير التطبيق.

يوجد نوعان من برامج التشغيل القياسية:

  • برامج التشغيل ODBC (Open DataBase Connectivity)
  • برامج التشغيل OLE و DB (ربط الكائنات وتضمينها DataBase)

تتيح برامج التشغيل ODBC الوصول إلى قواعد البيانات. أما مصادر البيانات لبرامج التشغيل OLE وDB فهي أكثر تنوعًا: قواعد البيانات، والبريد الإلكتروني، ودفاتر العناوين، ... ولا توجد أي قيود. يمكن لأي مصدر بيانات أن يكون موضوعًا لبرامج تشغيل OLE وDB إذا قرر الناشر ذلك. ومن الواضح أن الفائدة كبيرة: حيث يتوفر وصول موحد إلى مجموعة متنوعة من البيانات.

تأتي منصة .NET مزودة بنوعين من فئات الوصول إلى البيانات:

  1. فئتا SQL و Server.NET
  2. فئات OLE و Db.NET

تتيح الفئات الأولى الوصول المباشر إلى خادم Microsoft SGBD وSQL دون الحاجة إلى برنامج تشغيل وسيط. أما الفئات الثانية فتتيح الوصول إلى مصادر البيانات OLE وDB.

Image

يتم توفير منصة .NET (مايو 2002) مع ثلاثة برامج تشغيل OLE وDB مخصصة على التوالي لـ: SQL Server وOracle وMicrosoft Jet (Access). إذا أردنا العمل مع قاعدة بيانات تحتوي على برنامج تشغيل ODBC ولكن لا تحتوي على برامج التشغيل OLE وDB، فلن نتمكن من ذلك. وبالتالي، لا يمكن العمل مع SGBD و MySQL اللذين (في مايو 2002) لا يوفران برنامج تشغيل OLE و DB. ومع ذلك، توجد سلسلة من الفئات التي تتيح الوصول إلى مصادر البيانات، وهي فئات ODBC وodbc.net. ولا يتم توفيرها بشكل قياسي مع SDK، لذا يجب تنزيلها من موقع Microsoft. في الأمثلة التالية، سنستخدم بشكل أساسي هذه الفئات ODBC لأن معظم قواعد البيانات في نظام ويندوز تأتي مزودة ببرنامج تشغيل من هذا النوع. فيما يلي، على سبيل المثال، قائمة ببرامج التشغيل ODBC المثبتة على جهاز يعمل بنظام ويندوز 2000 (القائمة «ابدأ»/«الإعدادات»/«لوحة التحكم»/«أدوات الإدارة»):

Image

نختار أيقونة «مصدر البيانات» ODBC:

Image

7.2. طريقتان لاستخدام مصدر البيانات

تتيح منصة .NET تشغيل مصدر البيانات بطريقتين مختلفتين:

  1. الوضع المتصل
  2. الوضع غير المتصل

في الوضع المتصل، يقوم التطبيق

  1. اتصالًا بمصدر البيانات
  2. يعمل مع مصدر البيانات في وضع القراءة/الكتابة
  3. يغلق الاتصال

في وضع عدم الاتصال، يقوم التطبيق

  1. يفتح اتصالاً بمصدر البيانات
  2. يحصل على نسخة في الذاكرة من جميع بيانات المصدر أو جزء منها
  3. يغلق الاتصال
  4. يعمل على نسخة البيانات المخزنة في الذاكرة للقراءة والكتابة
  5. وعند انتهاء العمل، يفتح اتصالاً، ويرسل البيانات المعدلة إلى مصدر البيانات ليتم تضمينها فيه، ثم يغلق الاتصال

في كلتا الحالتين، فإن عملية معالجة البيانات وتحديثها هي التي تستغرق وقتًا. لنفترض أن هذه التحديثات يتم إجراؤها بواسطة مستخدم يقوم بإدخال البيانات، فقد تستغرق هذه العملية عشرات الدقائق. طوال هذا الوقت، في الوضع المتصل، يتم الحفاظ على الاتصال بقاعدة البيانات وتنعكس التعديلات على الفور. أما في الوضع غير المتصل، فلا يوجد اتصال بقاعدة البيانات أثناء تحديث البيانات. تُجرى التعديلات على النسخة المخزنة في الذاكرة فقط. وتُنقل إلى مصدر البيانات دفعة واحدة عند الانتهاء من كل شيء.

ما هي مزايا وعيوب هاتين الطريقتين؟

  • يستهلك الاتصال موارد نظامية كبيرة. في حالة وجود العديد من الاتصالات المتزامنة، يتيح الوضع غير المتصل تقليل مدة كل اتصال إلى الحد الأدنى. وهذا هو الحال بالنسبة لتطبيقات الويب التي تضم آلاف المستخدمين.
  • عيب الوضع غير المتصل هو الصعوبة في إدارة التحديثات المتزامنة. يحصل المستخدم U1 على البيانات في الوقت T1 ويبدأ في تعديلها. وفي الوقت T2، يصل المستخدم U2 أيضًا إلى مصدر البيانات ويحصل على نفس البيانات. وفي هذه الأثناء، قام المستخدم U1 بتعديل بعض البيانات ولكنه لم يقم بعد بإرسالها إلى مصدر البيانات. وبالتالي، يعمل U2 مع بيانات تحتوي على أخطاء. توفر فئات .NET حلولاً لإدارة هذه المشكلة، لكن حلها ليس بالأمر السهل.
  • في وضع الاتصال، لا يشكل التحديث المتزامن للبيانات من قبل عدة مستخدمين مشكلة في العادة. ونظرًا لاستمرار الاتصال بقاعدة البيانات، فإن قاعدة البيانات نفسها هي التي تدير عمليات التحديث المتزامنة هذه. وهكذا، تقوم Oracle بقفل سطر في قاعدة البيانات بمجرد قيام مستخدم ما بتعديله. وسيظل هذا السطر مقفلاً، وبالتالي غير متاح للمستخدمين الآخرين، إلى أن يقوم المستخدم الذي عدّله بتثبيت (commit) تعديله أو التراجع عنه (rollback).
  • إذا كان من الضروري نقل البيانات عبر الشبكة، فيجب اختيار الوضع غير المتصل. يتيح هذا الوضع الحصول على نسخة من البيانات في كائن يُسمى «مجموعة البيانات» (dataset) والذي يمثل قاعدة بيانات بحد ذاته. ويمكن نقل هذا الكائن عبر الشبكة بين الأجهزة.

سنقوم أولاً بدراسة الوضع المتصل.

7.3. الوصول إلى البيانات في الوضع المتصل

7.3.1. قواعد البيانات في المثال

نأخذ قاعدة بيانات ACCESS تُسمى articles.mdb وتحتوي على جدول واحد فقط يُسمى ARTICLES بالبنية التالية:

الاسم
النوع
الرمز
رمز المنتج المكون من 4 أحرف
الاسم
اسمه (سلسلة أحرف)
السعر
سعره (الفعلي)
stock_actuel
مخزونه الحالي (عدد صحيح)
stock_minimum
الحد الأدنى للمخزون (عدد صحيح) الذي يجب تجديد مخزون المنتج عنده

محتواه الأولي هو كما يلي:

Image

سنستخدم هذه القاعدة من خلال كل من المشروع التجريبي ODBC وبرنامج تجريبي OLE وDB لإظهار التشابه بين النهجين ولأننا نمتلك هذين النوعين من البرامج التجريبية لـ ACCESS.

كما سنستخدم قاعدة بيانات MySQL وDBARTICLES اللتين تحتويان على نفس الجدول الفريد ARTICLES، ونفس المحتوى، ويتم الوصول إليها عبر برنامج تشغيل ODBC، وذلك لإظهار أن التطبيق المكتوب لاستغلال قاعدة البيانات ACCESS لا يحتاج إلى تعديل لاستخدام قاعدة البيانات MySQL. يمكن الوصول إلى قاعدة البيانات DBARTICLES من قبل مستخدم يُدعى admarticles باستخدام كلمة المرور mdparticles. تُظهر لقطة الشاشة التالية محتوى قاعدة البيانات MySQL:

C:\mysql\bin>mysql --database=dbarticles --user=admarticles --password=mdparticles
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3 to server version: 3.23.49-max-debug

Type 'help' for help.


mysql> show tables;
+----------------------+
| Tables_in_dbarticles |
+----------------------+
| articles             |
+----------------------+
1 row in set (0.01 sec)

mysql> select * from articles;
+------+--------------------------------+------+--------------+---------------+
| code | nom                            | prix | stock_actuel | stock_minimum |
+------+--------------------------------+------+--------------+---------------+
| a300 | vÚlo                           | 2500 |           10 |             5 |
| b300 | pompe                          |   56 |           62 |            45 |
| c300 | arc                            | 3500 |           10 |            20 |
| d300 | flÞches - lot de 6             |  780 |           12 |            20 |
| e300 | combinaison de plongÚe         | 2800 |           34 |             7 |
| f300 | bouteilles d'oxygÞne           |  800 |           10 |             5 |
+------+--------------------------------+------+--------------+---------------+
6 rows in set (0.02 sec)

mysql> describe articles;
+---------------+-------------+------+-----+---------+-------+
| Field         | Type        | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| code          | text        | YES  |     | NULL    |       |
| nom           | text        | YES  |     | NULL    |       |
| prix          | double      | YES  |     | NULL    |       |
| stock_actuel  | smallint(6) | YES  |     | NULL    |       |
| stock_minimum | smallint(6) | YES  |     | NULL    |       |
+---------------+-------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> exit
Bye

لتعيين قاعدة البيانات ACCESS كمصدر بيانات لـ ODBC، اتبع الخطوات التالية:

  • قم بتفعيل «مدير مصادر البيانات» ODBC كما هو موضح أعلاه، ثم حدد علامة التبويب «المستخدم» DSN (DSN = اسم مصدر البيانات)

Image

  • أضف مصدرًا باستخدام الزر Add ، وحدد أن هذا المصدر يمكن الوصول إليه عبر برنامج تشغيل Access وقم بما يلي:

Image

  • أطلق اسم articles-access على مصدر البيانات، وأدخل وصفًا حرًا، واستخدم الزر Sélectionner لتعيين الملف .mdb من قاعدة البيانات. واختتم بـ OK.

Image

ستظهر مصدر البيانات الجديد بعد ذلك في قائمة مصادر المستخدم DSN:

Image

لتعيين قاعدة البيانات MySQL DBARTICLES كمصدر بيانات ODBC، اتبع الخطوات التالية:

  • قم بتفعيل «مدير مصادر البيانات» ODBC كما هو موضح أعلاه، ثم حدد علامة التبويب «المستخدم» DSN. أضف مصدر بيانات جديدًا باستخدام Add وحدد برنامج التشغيل ODBC الخاص بـ MySQL.

Image

  • قم بتنفيذ Terminer. ستظهر بعد ذلك صفحة تكوين مصدر MySQL:

54321

Image

  • في (1) نسمي مصدر البيانات الخاص بنا ODBC
  • في (2) نحدد الجهاز الذي يوجد عليه الخادم MySQL. هنا نضع localhost للإشارة إلى أنه موجود على نفس الجهاز الذي يعمل عليه تطبيقنا. إذا كان الخادم MySQL موجودًا على جهاز M بعيد، لكنا أدخلنا اسمه هنا، وعندها كان تطبيقنا سيعمل مع قاعدة بيانات بعيدة دون الحاجة إلى أي تعديل.
  • في (3) نضع اسم قاعدة البيانات. هنا يُسمى DBARTICLES.
  • في (4) نضع اسم المستخدم admarticles وفي (5) كلمة المرور mdparticles.

7.3.2. استخدام برنامج تشغيل ODBC

في أي تطبيق يستخدم قاعدة بيانات في وضع الاتصال، عادةً ما تتضمن الخطوات ما يلي:

  1. الاتصال بقاعدة البيانات
  2. إرسال الاستعلامات SQL إلى قاعدة البيانات
  3. استلام ومعالجة نتائج هذه الاستعلامات
  4. إغلاق الاتصال

يتم تنفيذ الخطوتين 2 و3 بشكل متكرر، ولا يتم إغلاق الاتصال إلا عند انتهاء عملية استغلال قاعدة البيانات. هذا نمط تقليدي نسبيًا قد تكون معتادًا عليه إذا كنت قد استخدمت قاعدة بيانات بشكل تفاعلي. هذه الخطوات هي نفسها سواء تم استخدام قاعدة البيانات من خلال برنامج تشغيل ODBC أو برنامج تشغيل OLE DB. نقدم أدناه مثالاً باستخدام فئات .NET لإدارة مصادر البيانات ODBC. يُسمى البرنامج liste ويقبل كمعلمة اسم DSN لمصدر بيانات ODBC يحتوي على جدول ARTICLES. ثم يعرض محتوى هذا الجدول:

dos>liste
syntaxe : pg dsnArticles

dos>liste articles-access

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

dos>liste mysql-artices
Erreur d'exploitation de la base de données (ERROR [IM002] [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified)

dos>liste mysql-articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

من النتائج أعلاه، نرى أن البرنامج قد أدرج محتوى كل من قاعدة البيانات ACCESS وقاعدة البيانات MySQL. دعونا الآن ندرس كود هذا البرنامج:


' خيارات
Option Explicit On 
Option Strict On

' مساحات الأسماء
Imports System
Imports System.Data
Imports Microsoft.Data.Odbc
Imports Microsoft.VisualBasic

Module db1
    Sub main(ByVal args As String())
        ' وحدة التحكم في التطبيق
        ' يعرض محتوى جدول ARTICLES من قاعدة بيانات DSN 
        ' التي تم تمرير اسمها كمعلمة
        Const syntaxe As String = "syntaxe : pg dsnArticles"
        Const tabArticles As String = "articles"        ' la table des articles

        ' التحقق من المعلمات
        ' هل يوجد معلمة واحدة
        If args.Length <> 1 Then
            ' رسالة خطأ
            Console.Error.WriteLine(syntaxe)
            ' النهاية
            Environment.Exit(1)
        End If

        ' استرداد المعلمة
        Dim dsnArticles As String = args(0)                ' la base DSN
        ' التحضير للاتصال بقاعدة البيانات
        Dim articlesConn As OdbcConnection = Nothing        ' la connexion
        Dim myReader As OdbcDataReader = Nothing            ' le lecteur de données

        ' محاولة الوصول إلى قاعدة البيانات
        Try
            ' سلسلة الاتصال بقاعدة البيانات
            Dim connectString As String = "DSN=" + dsnArticles + ";"
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()

            ' تنفيذ أمر SQL
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOdbcCommand As New OdbcCommand(sqlText)
            myOdbcCommand.Connection = articlesConn
            myReader = myOdbcCommand.ExecuteReader()

            ' استخراج البيانات من الجدول الذي تم استرداده
            ' عرض الأعمدة
            Dim ligne As String = ""
            Dim i As Integer
            For i = 0 To (myReader.FieldCount - 1) - 1
                ligne += myReader.GetName(i) + ","
            Next i
            ligne += myReader.GetName(i)
            Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))

            ' عرض البيانات
            While myReader.Read()
                ' معالجة السطر الحالي
                ligne = ""
                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i
                Console.WriteLine(ligne)
            End While
        Catch ex As Exception
            Console.Error.WriteLine(("Erreur d'exploitation de la base de données " + ex.Message + ")"))
            Environment.Exit(2)
        Finally
            ' إغلاق القارئ
            myReader.Close()
            ' إغلاق الاتصال
            articlesConn.Close()
        End Try
    End Sub
End Module

توجد فئات إدارة المصادر ODBC في مساحة الأسماء Microsoft.Data.Odbc، لذا يجب استيرادها. من ناحية أخرى، يوجد عدد من الفئات في مساحة الأسماء System.Data.


Imports System.Data
Imports Microsoft.Data.Odbc

توجد مساحات الأسماء التي يستخدمها البرنامج في تجميعات مختلفة. يتم ترجمة البرنامج باستخدام الأمر التالي:

dos>vbc /r:microsoft.data.odbc.dll /r:microsoft.visualbasic.dll /r:system.dll /r:system.data.dll db1.vb

7.3.2.1. مرحلة الاتصال

يستخدم الاتصال ODBC الفئة OdbcConnection. يقبل منشئ هذه الفئة كمعلمة ما يُسمى بسلسلة الاتصال. وهي عبارة عن سلسلة أحرف تحدد جميع المعلمات اللازمة لإجراء الاتصال بقاعدة البيانات. قد تكون هذه المعلمات كثيرة جدًا، وبالتالي تكون السلسلة معقدة. تتخذ السلسلة الشكل "param1=valeur1;param2=valeur2;...;paramj=valeurj;". وفيما يلي بعض المعلمات المحتملة لـ paramj:

uid
اسم المستخدم الذي سيقوم بالوصول إلى قاعدة البيانات
password
كلمة مرور هذا المستخدم
dsn
اسم قاعدة البيانات DSN إن كانت لها اسم
data source
اسم قاعدة البيانات التي تم الوصول إليها
...
 

إذا تم تعريف مصدر بيانات باسم ODBC باستخدام مدير مصادر البيانات ODBC، فإن هذه المعلمات قد تم تحديدها وتسجيلها بالفعل. ويكفي عندئذٍ تمرير المعلمة DSN التي تحدد اسم مصدر البيانات DSN. وهذا ما يتم هنا:


        ' التحضير للاتصال بقاعدة البيانات
        Dim articlesConn As OdbcConnection = Nothing        ' la connexion
        Dim myReader As OdbcDataReader = Nothing        ' le lecteur de données
        Try
            ' يتم محاولة الوصول إلى قاعدة البيانات
            ' سلسلة الاتصال بقاعدة البيانات
            Dim connectString As String = "DSN=" + dsnArticles + ";"
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()

بمجرد إنشاء الكائن OdbcConnection، يتم فتح الاتصال باستخدام الطريقة Open. قد يفشل هذا الفتح مثل أي عملية أخرى على قاعدة البيانات. ولهذا السبب، فإن كامل كود الوصول إلى قاعدة البيانات موجود في كائن try-catch. بمجرد إقامة الاتصال، يمكن إرسال استعلامات SQL إلى قاعدة البيانات.

7.3.2.2. إرسال استعلامات SQL

لإرسال استعلامات SQL، نحتاج إلى كائن Command، وبالتحديد هنا كائن OdbcCommand نظرًا لأننا نستخدم مصدر بيانات ODBC. تحتوي الفئة OdbcCommand على عدة منشئات:

  • OdbcCommand(): تُنشئ كائن Command فارغًا. وللاستفادة منه، سيتعين تحديد خصائص متنوعة لاحقًا:
    • CommandText: نص الاستعلام SQL المراد تنفيذه
    • Connection: الكائن OdbcConnection الذي يمثل الاتصال بقاعدة البيانات التي سيتم إجراء الاستعلام عليها
    • CommandType: نوع الاستعلام SQL. هناك ثلاث قيم ممكنة
  1. CommandType.Text: تحتوي الخاصية CommandText على نص استعلام SQL (القيمة الافتراضية)
  2. CommandType.StoredProcedure: تحتوي الخاصية CommandText على اسم إجراء مخزن في قاعدة البيانات
  3. CommandType.TableDirect: تحتوي الخاصية CommandText على اسم جدول T. تعادل عبارة select * from T. لا توجد إلا في برامج التشغيل OLE وDB.
  • OdbcCommand(string sqlText): سيتم تعيين المعلمة sqlText إلى الخاصية CommandText. هذا هو نص الاستعلام SQL المطلوب تنفيذه. يجب تحديد الاتصال في الخاصية Connection.
  • OdbcCommand(string sqlText, OdbcConnection اتصال): سيتم تعيين المعلمة sqlText إلى الخاصية CommandText، والمعلمة connexion إلى الخاصية Connection.

لإرسال الاستعلام SQL، تتوفر طريقتان:

  • OdbcdataReader ExecuteReader(): يرسل الاستعلام SELECT من CommandText إلى الاتصال Connection ويقوم بإنشاء كائن OdbcDataReader الذي يتيحالوصول إلى جميع الصفوف في جدول نتائج select
  • int ExecuteNOnQuery(): يرسل طلب التحديث (INSERT، UPDATE، DELETE) من CommandText إلى اتصال Connection وتُرجع عدد الأسطر المتأثرة بهذا التحديث.

في مثالنا، بعد فتح الاتصال بقاعدة البيانات، نرسل استعلامًا SQL SELECT للحصول على محتوى الجدول ARTICLES:


            ' تنفيذ أمر SQL
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOdbcCommand As New OdbcCommand(sqlText)
            myOdbcCommand.Connection = articlesConn
            myReader = myOdbcCommand.ExecuteReader()

عادةً ما تكون استعلامات الاستعلام من النوع التالي:

    select col1, col2,... from table1, table2,...
    where condition
    order by expression
    ...

الكلمات الرئيسية في السطر الأول هي فقط التي تُعد إلزامية، أما البقية فهي اختيارية. وهناك كلمات رئيسية أخرى غير مذكورة هنا.

  1. يتم إجراء عملية ربط مع جميع الجداول الموجودة بعد الكلمة الرئيسية «from»
  2. يتم الاحتفاظ فقط بالأعمدة الموجودة بعد الكلمة الرئيسية "select"
  3. يتم الاحتفاظ فقط بالصفوف التي تستوفي شرط الكلمة الرئيسية «where»
  4. تشكل الأسطر الناتجة، المرتبة وفقًا للتعبير الوارد في الكلمة الرئيسية «order by»، نتيجة الاستعلام.

نتيجة select هي جدول. إذا أخذنا الجدول ARTICLES السابق في الاعتبار وأردنا الحصول على أسماء الأصناف التي يقل مخزونها الحالي عن الحد الأدنى، فسنكتب:

    select nom from articles where stock_actuel<stock_minimum

وإذا أردنا ترتيبها أبجديًّا حسب الأسماء، فسنكتب:

    select nom from articles where stock_actuel<stock_minimum order by nom

7.3.2.3. استغلال نتيجة استعلام SELECT

نتيجة الاستعلام SELECT في الوضع غير المتصل هي كائن DataReader، وهنا كائن OdbcDataReader. يتيح هذا الكائن الحصول على جميع صفوف النتيجة بالتسلسل والحصول على معلومات حول أعمدة هذه النتائج. دعونا نستعرض بعض خصائص وأساليب هذه الفئة:

FieldCount
عدد أعمدة الجدول
Item
Item(i) يمثل العمود رقم i في السطر الحالي من النتيجة
XXX GetXXX(i)
قيمة العمود رقم i في السطر الحالي معروضة كنوع XXX (Int16، Int32، Int64، Double، String، Boolean، ...)
string GetName(i)
اسم العمود رقم i
Close()
يغلق الكائن OdbcdataReader ويحرر الموارد المرتبطة به
bool Read()
يتقدم سطرًا واحدًا في جدول النتائج. يُرجع قيمة "خطأ" إذا تعذر ذلك. يصبح السطر الجديد هو السطر الحالي للقارئ.

عادةً ما تكون معالجة نتيجة select معالجة متسلسلة مشابهة لتلك الخاصة بالملفات النصية: لا يمكن إلا التقدم في الجدول، ولا يمكن الرجوع إلى الوراء:


While myReader.Read()
    ' توجد سجل - يتم معالجته
    ....
    ' السطر التالي
end while

هذه التفسيرات كافية لفهم الكود التالي في مثالنا:


            ' استغلال الجدول المسترد
            ' عرض الأعمدة
            Dim ligne As String = ""
            Dim i As Integer
            For i = 0 To (myReader.FieldCount - 1) - 1
                ligne += myReader.GetName(i) + ","
            Next i
            ligne += myReader.GetName(i)
            Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))

            ' عرض البيانات
            While myReader.Read()
                ' معالجة السطر الحالي
                ligne = ""
                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i
                Console.WriteLine(ligne)
            End While

تكمن الصعوبة الوحيدة في الأمر الذي يتم فيه ربط قيم الأعمدة المختلفة في السطر الحالي:


                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i

يُترجم الترميز «السطر+=myReader(i).ToString» إلى «السطر+=myReader.Item(i)».ToString() حيث Item(i) هي قيمة العمود i في السطر الحالي.

7.3.2.4. تحرير الموارد

تحتوي كل من الفئتين OdbcReader و OdbcConnection على طريقة Close() التي تحرر الموارد المرتبطة بالكائنات التي تم إغلاقها.

                ' إغلاق القارئ
                myReader.Close()
                ' إغلاق الاتصال
                articlesConn.Close()

7.3.3. استخدام برنامج تشغيل OLE DB

سنستخدم المثال نفسه، ولكن هذه المرة مع قاعدة بيانات يتم الوصول إليها عبر برنامج تشغيل OLE DB. توفر منصة .NET برنامج تشغيل من هذا النوع لقواعد البيانات ACCESS. ولذلك سنستخدم نفس قاعدة البيانات articles.mdb التي استخدمناها سابقًا. ونسعى هنا إلى توضيح أنه حتى لو تغيرت الفئات، فإن المفاهيم تظل كما هي:

  • يتم تمثيل الاتصال بكائن OleDbConnection
  • يتم إرسال استعلام SQL بواسطة كائن OleDbCommand
  • وإذا كان هذا الاستعلام عبارة عن جملة SELECT، فسنحصل في المقابل على كائن OleDbDataReader للوصول إلى صفوف جدول النتائج

توجد هذه الفئات في مساحة الأسماء System.Data.OleDb. يمكن تعديل البرنامج السابق بسهولة للتعامل مع قاعدة بيانات OLE DB:

  • يتم استبدال OdbcXX بـ OleDbXX في جميع الأماكن
  • يتم تعديل سلسلة الاتصال. بالنسبة لقاعدة بيانات ACCESS التي لا تتطلب اسم مستخدم/كلمة مرور، تكون سلسلة الاتصال هي Provider=Microsoft.JET.OLEDB.4.0;Data Source=[fichier.mdb]. الجزء القابل للتعيين في هذه السلسلة هو اسم الملف ACCESS المراد استخدامه. سنقوم بتعديل برنامجنا ليقبل اسم هذا الملف كمعلمة.
  • أصبح مساحة الأسماء المراد استيرادها الآن هي System.Data.OleDb.

يصبح برنامجنا كما يلي:


' خيارات
Option Explicit On 
Option Strict On

' مساحات الأسماء
Imports System
Imports System.Data
Imports Microsoft.Data.Odbc
Imports Microsoft.VisualBasic
Imports System.Data.OleDb

Module db2
    Public Sub Main(ByVal args() As String)

        ' وحدة التحكم في التطبيق
        ' يعرض محتوى جدول ARRTICLES في قاعدة بيانات DSN 
        ' التي تم تمرير اسمها كمعلمة
        Const syntaxe As String = "syntaxe : pg base_access_articles"
        Const tabArticles As String = "articles"        ' la table des articles

        ' التحقق من المعلمات
        ' هل يوجد معلمة واحدة
        If args.Length <> 1 Then
            ' رسالة خطأ
            Console.Error.WriteLine(syntaxe)
            ' النهاية
            Environment.Exit(1)
        End If

        ' استرداد المعلمة
        Dim dbArticles As String = args(0)        ' la base de données

        ' التحضير للاتصال بقاعدة البيانات
        Dim articlesConn As OleDbConnection = Nothing        ' la connexion
        Dim myReader As OleDbDataReader = Nothing        ' le lecteur de données

        ' محاولة الوصول إلى قاعدة البيانات

        Try
            ' سلسلة الاتصال بقاعدة البيانات
            Dim connectString As String = "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + dbArticles + ";"
            articlesConn = New OleDbConnection(connectString)
            articlesConn.Open()

            ' تنفيذ أمر SQL
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOleDbCommand As New OleDbCommand(sqlText)
            myOleDbCommand.Connection = articlesConn
            myReader = myOleDbCommand.ExecuteReader()

            ' استخراج البيانات من الجدول الذي تم استرداده
            ' عرض الأعمدة
            Dim ligne As String = ""
            Dim i As Integer
            For i = 0 To (myReader.FieldCount - 1) - 1
                ligne += myReader.GetName(i) + ","
            Next i
            ligne += myReader.GetName(i)
            Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))
            ' عرض البيانات
            While myReader.Read()
                ' معالجة السطر الحالي
                ligne = ""
                For i = 0 To myReader.FieldCount - 1
                    ligne += myReader(i).ToString + " "
                Next i
                Console.WriteLine(ligne)
            End While
        Catch ex As Exception
            Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
            Environment.Exit(2)
        Finally
            ' إغلاق القارئ
                myReader.Close()
                ' إغلاق الاتصال
                articlesConn.Close()
        End Try
        ' النهاية
        Environment.Exit(0)
    End Sub
End Module

النتائج التي تم الحصول عليها:

dos>vbc liste.vb

E:\data\serge\MSNET\vb.net\adonet\6>dir
07/05/2002  15:09                2 325 liste.CS
07/05/2002  15:09                4 608 liste.exe
20/08/2001  11:54               86 016 ARTICLES.MDB

dos>liste articles.mdb

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

7.3.4. تحديث جدول

اكتفت الأمثلة السابقة بعرض محتويات الجدول. سنقوم بتعديل برنامج إدارة قاعدة بيانات المواد بحيث يتمكن من تعديلها. يُسمى البرنامج sql. يتم تمرير اسم قاعدة بيانات المواد المراد إدارتها، DSN، كمعلمة للبرنامج. يقوم المستخدم بكتابة الأوامر SQL مباشرةً على لوحة المفاتيح، ويقوم البرنامج بتنفيذها كما توضح النتائج التالية التي تم الحصول عليها من قاعدة بيانات المواد MySQL:

dos>vbc /r:microsoft.data.odbc.dll sql.vb

dos>sql mysql-articles

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

Requête SQL (fin pour arrêter) : select * from articles where stock_actuel<stock_minimum

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20

Requête SQL (fin pour arrêter) : insert into articles values ("1","1",1,1,1)
Il y a eu 1 ligne(s) modifiée(s)

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5
1 1 1 1 1

Requête SQL (fin pour arrêter) : update articles set nom="2" where nom="1"
Il y a eu 1 ligne(s) modifiée(s)

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5
1 2 1 1 1

Requête SQL (fin pour arrêter) : delete from articles where code="1"
Il y a eu 1 ligne(s) modifiée(s)

Requête SQL (fin pour arrêter) : select * from articles

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

a300 vélo                           2500 10 5
b300 pompe                          56 62 45
c300 arc                            3500 10 20
d300 flèches - lot de 6             780 12 20
e300 combinaison de plongée         2800 34 7
f300 bouteilles d'oxygène           800 10 5

Requête SQL (fin pour arrêter) : select * from articles order by nom asc

----------------------------------------
code,nom,prix,stock_actuel,stock_minimum
----------------------------------------

c300 arc                            3500 10 20
f300 bouteilles d'oxygène           800 10 5
e300 combinaison de plongée         2800 34 7
d300 flèches - lot de 6             780 12 20
b300 pompe                          56 62 45
a300 vélo                           2500 10 5

Requête SQL (fin pour arrêter) : fin

البرنامج كالتالي:


' خيارات
Option Explicit On 
Option Strict On

' مساحات الأسماء
Imports System
Imports System.Data
Imports Microsoft.Data.Odbc
Imports System.Data.OleDb
Imports System.Text.RegularExpressions
Imports System.Collections
Imports Microsoft.VisualBasic

Module db3
    Public Sub Main(ByVal args() As String)

        ' وحدة التحكم في التطبيق
        ' تنفيذ الاستعلامات التي يتم إدخالها عبر لوحة المفاتيح على 
        ' جدول ARTICLES في قاعدة بيانات DSN يتم تمرير اسمها كمعلمة
        Const syntaxe As String = "syntaxe : pg dsnArticles"

        ' التحقق من المعلمات
        ' هل لدينا معلمتان
        If args.Length <> 1 Then
            ' رسالة خطأ
            Console.Error.WriteLine(syntaxe)
            ' نهاية
            Environment.Exit(1)
        End If        'if
        ' يتم استرداد المعلمة
        Dim dsnArticles As String = args(0)
        ' سلسلة الاتصال بقاعدة البيانات
        Dim connectString As String = "DSN=" + dsnArticles + ";"

        ' التحضير للاتصال بقاعدة البيانات
        Dim articlesConn As OdbcConnection = Nothing
        Dim sqlCommand As OdbcCommand = Nothing
        Try
            ' محاولة الوصول إلى قاعدة البيانات
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()
            ' يتم إنشاء كائن أمر
            sqlCommand = New OdbcCommand("", articlesConn)
            'محاولة
        Catch ex As Exception
            ' رسالة خطأ
            Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
            ' تحرير الموارد
            Try
                articlesConn.Close()
            Catch
            End Try
            Environment.Exit(2)
        End Try        'catch
        ' يتم إنشاء قاموس للأوامر SQL المقبولة
        Dim commandesSQL() As String = {"select", "insert", "update", "delete"}
        Dim dicoCommandes As New Hashtable
        Dim i As Integer
        For i = 0 To commandesSQL.Length - 1
            dicoCommandes.Add(commandesSQL(i), True)
        Next i

        ' قراءة وتنفيذ الأوامر SQL التي تم إدخالها عبر لوحة المفاتيح
        Dim requête As String = Nothing        ' texte de la requête SQL
        Dim champs() As String        ' les champs de la requête    
        Dim modèle As New Regex("\s+")
        ' حلقة الإدخال والتنفيذ للأوامر SQL التي تمت كتابتها عبر لوحة المفاتيح
        While True
            ' لا توجد أخطاء في البداية
            Dim erreur As Boolean = False
            ' طلب الاستعلام
            Console.Out.Write(ControlChars.Lf + "Requête SQL (fin pour arrêter) : ")
            requête = Console.In.ReadLine().Trim().ToLower()
            ' انتهى؟
            If requête = "fin" Then
                Exit While
            End If
            ' تقسيم الاستعلام إلى حقول
            champs = modèle.Split(requête)
            ' هل الاستعلام صحيح؟
            If champs.Length = 0 Or Not dicoCommandes.ContainsKey(champs(0)) Then
                ' رسالة خطأ
                Console.Error.WriteLine("Requête invalide. Utilisez select, insert, update, delete")
                ' الاستعلام التالي
                erreur = True
            End If
            If Not erreur Then
                ' تحضير كائن Command لتنفيذ الاستعلام
                sqlCommand.CommandText = requête
                ' تنفيذ الطلب
                Try
                    If champs(0) = "select" Then
                        executeSelect(sqlCommand)
                    Else
                        executeUpdate(sqlCommand)
                    End If
                Catch ex As Exception
                    ' رسالة خطأ
                    Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
                End Try
            End If
        End While
        ' تحرير الموارد
        Try
            articlesConn.Close()
        Catch
        End Try
        Environment.Exit(0)
    End Sub

    ' تنفيذ طلب تحديث
    Sub executeUpdate(ByVal sqlCommand As OdbcCommand)
        ' تنفيذ sqlCommand، طلب التحديث
        Dim nbLignes As Integer = sqlCommand.ExecuteNonQuery()
        ' العرض
        Console.Out.WriteLine(("Il y a eu " & nbLignes & " ligne(s) modifiée(s)"))
    End Sub

    ' تنفيذ استعلام Select
    Sub executeSelect(ByVal sqlCommand As OdbcCommand)
        ' يُنفذ sqlCommand، استعلام Select
        Dim myReader As OdbcDataReader = sqlCommand.ExecuteReader()
        ' استخراج البيانات من الجدول الذي تم استرداده
        ' عرض الأعمدة
        Dim ligne As String = ""
        Dim i As Integer
        For i = 0 To (myReader.FieldCount - 1) - 1
            ligne += myReader.GetName(i) + ","
        Next i
        ligne += myReader.GetName(i)
        Console.Out.WriteLine((ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf + ligne + ControlChars.Lf + "".PadLeft(ligne.Length, "-"c) + ControlChars.Lf))
        ' عرض البيانات
        While myReader.Read()
            ' معالجة السطر الحالي
            ligne = ""
            For i = 0 To myReader.FieldCount - 1
                ligne += myReader(i).ToString + " "
            Next i
            ' العرض
            Console.WriteLine(ligne)
        End While
        ' تحرير الموارد
        myReader.Close()
    End Sub
End Module

لن نعلق هنا إلا على ما هو جديد مقارنة بالبرنامج السابق:

  • نقوم بإنشاء قاموس للأوامر SQL المقبولة:

        ' يتم إنشاء قاموس للأوامر SQL المقبولة
        Dim commandesSQL() As String = {"select", "insert", "update", "delete"}
        Dim dicoCommandes As New Hashtable
        Dim i As Integer
        For i = 0 To commandesSQL.Length - 1
            dicoCommandes.Add(commandesSQL(i), True)
        Next i

مما يتيح لنا بعد ذلك التحقق بسهولة مما إذا كانت الكلمة الأولى (الحقل [0]) من الاستعلام المكتوب هي إحدى الأوامر الأربعة المقبولة:


            ' هل الاستعلام صالح؟
            If champs.Length = 0 Or Not dicoCommandes.ContainsKey(champs(0)) Then
                ' رسالة خطأ
                Console.Error.WriteLine("Requête invalide. Utilisez select, insert, update, delete")
                ' الاستعلام التالي
                erreur = True
            End If            'if
  • في السابق، كان الاستعلام يُقسَّم إلى حقول باستخدام الطريقة Split التابعة للفئة RegEx:

        Dim modèle As New Regex("\s+")
....
            ' يتم تقسيم الاستعلام إلى حقول
            champs = modèle.Split(requête)

يمكن فصل الكلمات المكونة للاستعلام بأي عدد من المسافات.

  • لا يستخدم تنفيذ الاستعلام select نفس الطريقة المستخدمة في استعلام التحديث (insert، update، delete). لذلك، يجب إجراء اختبار وتنفيذ دالة مختلفة لكل من هاتين الحالتين:

                ' تحضير كائن Command لتنفيذ الاستعلام
                sqlCommand.CommandText = requête
                ' تنفيذ الاستعلام
                Try
                    If champs(0) = "select" Then
                        executeSelect(sqlCommand)
                    Else
                        executeUpdate(sqlCommand)
                    End If                    'try
                Catch ex As Exception
                    ' رسالة خطأ
                    Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
                End Try

قد يؤدي تنفيذ الاستعلام SQL إلى حدوث استثناء يتم معالجته هنا.

  • تستعرض الدالة executeSelect كل ما تم تناوله في الأمثلة السابقة.
  • تستخدم الدالة executeUpdate الطريقة ExecuteNonQuery من الفئة OdbcCommand التي تُرجع عدد الأسطر التي تأثرت بالأمر.

7.3.5. IMPOTS

نستعيد الكائن impôt الذي تم إنشاؤه في فصل سابق:


' خيارات
Option Strict On
Option Explicit On 

' مساحات الأسماء
Imports System

Public Class impôt
    ' البيانات اللازمة لحساب الضريبة
    ' تأتي من مصدر خارجي
    Private limites(), coeffR(), coeffN() As Decimal

    ' المُنشئ
    Public Sub New(ByVal LIMITES() As Decimal, ByVal COEFFR() As Decimal, ByVal COEFFN() As Decimal)
        ' يتم التحقق من أن الجداول الثلاثة لها نفس الحجم
        Dim OK As Boolean = LIMITES.Length = COEFFR.Length And LIMITES.Length = COEFFN.Length
        If Not OK Then
            Throw New Exception("Les 3 tableaux fournis n'ont pas la même taille(" & LIMITES.Length & "," & COEFFR.Length & "," & COEFFN.Length & ")")
        End If
        ' لا بأس
        Me.limites = LIMITES
        Me.coeffR = COEFFR
        Me.coeffN = COEFFN
    End Sub

    ' حساب الضريبة
    Public Function calculer(ByVal marié As Boolean, ByVal nbEnfants As Integer, ByVal salaire As Integer) As Long
        ' حساب عدد الحصص
        Dim nbParts As Decimal
        If marié Then
            nbParts = CDec(nbEnfants) / 2 + 2
        Else
            nbParts = CDec(nbEnfants) / 2 + 1
        End If
        If nbEnfants >= 3 Then
            nbParts += 0.5D
        End If
        ' حساب الدخل الخاضع للضريبة و«الناتج العائلي»
        Dim revenu As Decimal = 0.72D * salaire
        Dim QF As Decimal = revenu / nbParts
        ' حساب الضريبة
        limites((limites.Length - 1)) = QF + 1
        Dim i As Integer = 0
        While QF > limites(i)
            i += 1
        End While
        ' إرجاع النتيجة
        Return CLng(revenu * coeffR(i) - nbParts * coeffN(i))
    End Function
End Class

نضيف إليه منشئًا جديدًا يسمح بتهيئة المصفوفات limites و coeffR و coeffN انطلاقًا من قاعدة البيانات ODBC:


Imports System.Data
Imports Microsoft.Data.Odbc
Imports System.Collections
...


    ' المنشئ 2
    Public Sub New(ByVal DSNimpots As String, ByVal Timpots As String, ByVal colLimites As String, ByVal colCoeffR As String, ByVal colCoeffN As String)
        ' تهيئة الجداول الثلاثة للحدود، coeffR، coeffN استنادًا
        ' محتوى الجدول Timpots في قاعدة البيانات ODBC DSNimpots
        ' colLimites، colCoeffR، colCoeffN هي الأعمدة الثلاثة في هذا الجدول
        ' قد يثير استثناءً
        Dim connectString As String = "DSN=" + DSNimpots + ";"        ' chaîne de connexion à la base
        Dim impotsConn As OdbcConnection = Nothing        ' la connexion
        Dim sqlCommand As OdbcCommand = Nothing        ' la commande SQL
        ' الاستعلام SELECT
        Dim selectCommand As String = "select " + colLimites + "," + colCoeffR + "," + colCoeffN + " from " + Timpots
        ' جداول لاسترداد البيانات
        Dim tLimites As New ArrayList
        Dim tCoeffR As New ArrayList
        Dim tCoeffN As New ArrayList

        ' يتم محاولة الوصول إلى قاعدة البيانات
        impotsConn = New OdbcConnection(connectString)
        impotsConn.Open()
        ' يتم إنشاء كائن أمر
        sqlCommand = New OdbcCommand(selectCommand, impotsConn)
        ' يتم تنفيذ الاستعلام
        Dim myReader As OdbcDataReader = sqlCommand.ExecuteReader()
        ' استغلال الجدول الذي تم استرداده
        While myReader.Read()
            ' يتم وضع بيانات السطر الحالي في الجداول
            tLimites.Add(myReader(colLimites))
            tCoeffR.Add(myReader(colCoeffR))
            tCoeffN.Add(myReader(colCoeffN))
        End While
        ' تحرير الموارد
        myReader.Close()
        impotsConn.Close()

        ' يتم تحويل المصفوفات الديناميكية إلى مصفوفات ثابتة
        Me.limites = New Decimal(tLimites.Count) {}
        Me.coeffR = New Decimal(tLimites.Count) {}
        Me.coeffN = New Decimal(tLimites.Count) {}
        Dim i As Integer
        For i = 0 To tLimites.Count - 1
            limites(i) = Decimal.Parse(tLimites(i).ToString())
            coeffR(i) = Decimal.Parse(tCoeffR(i).ToString())
            coeffN(i) = Decimal.Parse(tCoeffN(i).ToString())
        Next i
    End Sub

برنامج الاختبار هو كما يلي: يتلقى كمعلمات المعلمات التي يجب تمريرها إلى منشئ الفئة impôt. بعد إنشاء كائن impôt، يقوم بإجراء حسابات الضريبة المستحقة:


Option Explicit On 
Option Strict On

' مساحات الأسماء
Imports System
Imports Microsoft.VisualBasic

' صفحة اختبار
Module testimpots
    Sub Main(ByVal arguments() As String)
        ' برنامج تفاعلي لحساب الضرائب
        ' يقوم المستخدم بإدخال ثلاث بيانات عبر لوحة المفاتيح: متزوج nbEnfants الراتب
        ' ثم يعرض البرنامج الضريبة المستحقة
        Const syntaxe1 As String = "pg DSNimpots tabImpots colLimites colCoeffR colCoeffN"
        Const syntaxe2 As String = "syntaxe : marié nbEnfants salaire" + ControlChars.Lf + "marié : o pour marié, n pour non marié" + ControlChars.Lf + "nbEnfants : nombre d'enfants" + ControlChars.Lf + "salaire : salaire annuel en F"

        ' التحقق من معلمات البرنامج
        If arguments.Length <> 5 Then
            ' رسالة خطأ
            Console.Error.WriteLine(syntaxe1)
            ' نهاية
            Environment.Exit(1)
        End If        'if
        ' يتم استرداد المعلمات
        Dim DSNimpots As String = arguments(0)
        Dim tabImpots As String = arguments(1)
        Dim colLimites As String = arguments(2)
        Dim colCoeffR As String = arguments(3)
        Dim colCoeffN As String = arguments(4)

        ' إنشاء كائن ضريبة
        Dim objImpôt As impôt = Nothing
        Try
            objImpôt = New impôt(DSNimpots, tabImpots, colLimites, colCoeffR, colCoeffN)
        Catch ex As Exception
            Console.Error.WriteLine(("L'erreur suivante s'est produite : " + ex.Message))
            Environment.Exit(2)
        End Try

        ' حلقة لا نهائية
        While True
            ' في البداية لا توجد أخطاء
            Dim erreur As Boolean = False

            ' يُطلب إدخال معلمات حساب الضريبة
            Console.Out.Write("Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :")
            Dim paramètres As String = Console.In.ReadLine().Trim()

            ' هل هناك ما يجب فعله؟
            If paramètres Is Nothing Or paramètres = "" Then
                Exit While
            End If

            ' التحقق من عدد المعلمات في السطر الذي تم إدخاله
            Dim args As String() = paramètres.Split(Nothing)
            Dim nbParamètres As Integer = args.Length
            If nbParamètres <> 3 Then
                Console.Error.WriteLine(syntaxe2)
                erreur = True
            End If
            Dim marié As String
            Dim nbEnfants As Integer
            Dim salaire As Integer
            If Not erreur Then
                ' التحقق من صحة المعلمات
                ' متزوج
                marié = args(0).ToLower()
                If marié <> "o" And marié <> "n" Then
                    Console.Error.WriteLine((syntaxe2 + ControlChars.Lf + "Argument marié incorrect : tapez o ou n"))
                    erreur = True
                End If
                ' nbEnfants
                nbEnfants = 0
                Try
                    nbEnfants = Integer.Parse(args(1))
                    If nbEnfants < 0 Then
                        Throw New Exception
                    End If
                Catch
                    Console.Error.WriteLine(syntaxe2 + "\nArgument nbEnfants incorrect : tapez un entier positif ou nul")
                    erreur = True
                End Try
                ' الراتب
                salaire = 0
                Try
                    salaire = Integer.Parse(args(2))
                    If salaire < 0 Then
                        Throw New Exception
                    End If
                Catch
                    Console.Error.WriteLine(syntaxe2 + "\nArgument salaire incorrect : tapez un entier positif ou nul")
                    erreur = True
                End Try
            End If
            If Not erreur Then
                ' المعلمات صحيحة - يتم حساب الضريبة
                Console.Out.WriteLine(("impôt=" & objImpôt.calculer(marié = "o", nbEnfants, salaire).ToString + " F"))
            End If
        End While
    End Sub
End Module

القاعدة المستخدمة هي قاعدة MySQL التي تحمل الاسم DSN mysql-impots:

C:\mysql\bin>mysql --database=impots --user=admimpots --password=mdpimpots
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5 to server version: 3.23.49-max-debug

Type 'help' for help.

mysql> show tables;
+------------------+
| Tables_in_impots |
+------------------+
| timpots          |
+------------------+

mysql> select * from timpots;
+---------+--------+---------+
| limites | coeffR | coeffN  |
+---------+--------+---------+
|   12620 |      0 |       0 |
|   13190 |   0.05 |     631 |
|   15640 |    0.1 |  1290.5 |
|   24740 |   0.15 |  2072.5 |
|   31810 |    0.2 |  3309.5 |
|   39970 |   0.25 |    4900 |
|   48360 |    0.3 |    6898 |
|   55790 |   0.35 |  9316.5 |
|   92970 |    0.4 |   12106 |
|  127860 |   0.45 |   16754 |
|  151250 |    0.5 | 23147.5 |
|  172040 |   0.55 |   30710 |
|  195000 |    0.6 |   39312 |
|       0 |   0.65 |   49062 |
+---------+--------+---------+

يُعطِي تنفيذ برنامج الاختبار النتائج التالية:

dos>D:\data\devel\vbnet\poly\chap6\impots>vbc /r:system.data.dll /r:microsoft.data.odbc.dll /r:system.dll /t:library impots.vb

dos>vbc /r:impots.dll testimpots.vb

dos>test mysql-impots timpots limites coeffr coeffn
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :o 2 200000
impôt=22506 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :n 2 200000
impôt=33388 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :o 3 200000
impôt=16400 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :n 3 300000
impôt=50082 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :n 3 200000
impôt=22506 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :