Skip to content

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

7.1. عام

هناك العديد من قواعد البيانات المتاحة لمنصات Windows. للوصول إليها، تستخدم التطبيقات برامج تسمى برامج التشغيل.

في الرسم التوضيحي أعلاه، يحتوي برنامج التشغيل على واجهتين:

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

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

هناك نوعان من برامج التشغيل المعيارية:

  • برامج تشغيل ODBC (اتصال قاعدة البيانات المفتوحة)
  • برامج تشغيل OLE DB (ربط الكائنات وتضمين قاعدة البيانات)

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

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

  1. فئات SQL Server.NET
  2. فئات OLE DB.NET

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

Image

يتم توفير منصة .NET (اعتبارًا من مايو 2002) بثلاثة برامج تشغيل OLE DB لـ SQL Server و Oracle و Microsoft Jet (Access) على التوالي. إذا كنت ترغب في العمل مع قاعدة بيانات تحتوي على برنامج تشغيل ODBC ولكن لا تحتوي على برنامج تشغيل OLE DB، فلن تتمكن من ذلك. وبالتالي، لا يمكنك العمل مع نظام إدارة قواعد البيانات MySQL، الذي (اعتبارًا من مايو 2002) لا يوفر برنامج تشغيل OLE DB. ومع ذلك، هناك مجموعة من الفئات التي تتيح الوصول إلى مصادر بيانات ODBC: فئات odbc.net. هذه الفئات غير مضمنة افتراضيًا في SDK ويجب تنزيلها من موقع Microsoft على الويب. في الأمثلة التالية، سنستخدم بشكل أساسي فئات ODBC هذه لأن معظم قواعد البيانات على Windows تأتي مع برنامج تشغيل من هذا النوع. فيما يلي، على سبيل المثال، قائمة ببرامج تشغيل ODBC المثبتة على جهاز يعمل بنظام Windows 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 بقفل صف في قاعدة البيانات بمجرد قيام مستخدم بتعديله. وسيظل مقفلاً — وبالتالي غير متاح للمستخدمين الآخرين — حتى يقوم المستخدم الذي عدّله بتثبيت التغيير أو التراجع عنه.
  • إذا كانت هناك حاجة لمشاركة البيانات عبر الشبكة، فيجب عليك اختيار الوضع غير المتصل. يوفر هذا الوضع لقطة من البيانات في كائن يسمى مجموعة البيانات، والذي يعمل كقاعدة بيانات مستقلة. يمكن مشاركة هذا الكائن عبر الشبكة بين الأجهزة.

سنقوم أولاً بفحص الوضع المتصل.

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

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

نحن ننظر في قاعدة بيانات Access تسمى articles.mdb تحتوي على جدول واحد فقط يسمى ARTICLES بالهيكل التالي:

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

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

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

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

Image

  • قم بتسمية مصدر البيانات "articles-access"، وأدخل الوصف الذي تختاره، واستخدم زر "تحديد" لتحديد ملف .mdb الخاص بقاعدة البيانات. أنهي العملية بالنقر فوق "موافق".

Image

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

Image

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

  • افتح "مدير مصادر بيانات ODBC" كما هو موضح أعلاه وحدد علامة التبويب "DSN المستخدم". أضف مصدر بيانات جديدًا باستخدام "إضافة" وحدد برنامج تشغيل MySQL ODBC.

Image

  • انقر فوق "إنهاء". ستظهر بعد ذلك صفحة تكوين مصدر 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. دعونا الآن نفحص كود هذا البرنامج:


' options
Option Explicit On 
Option Strict On

' namespaces
Imports System
Imports System.Data
Imports Microsoft.Data.Odbc
Imports Microsoft.VisualBasic
 
Module db1
    Sub main(ByVal args As String())
        ' application console
        ' displays the contents of a ARTICLES table in a DSN database 
        ' whose name is passed in parameter
        Const syntaxe As String = "syntaxe : pg dsnArticles"
        Const tabArticles As String = "articles"        ' table of articles
 
        ' parameter verification
        ' do we have 1 parameter
        If args.Length <> 1 Then
            ' error msg
            Console.Error.WriteLine(syntaxe)
            ' end
            Environment.Exit(1)
        End If
 
        ' parameter is retrieved
        Dim dsnArticles As String = args(0)                ' the DSN database
        ' preparing the connection to the comic
        Dim articlesConn As OdbcConnection = Nothing        ' the connection
        Dim myReader As OdbcDataReader = Nothing            ' the data reader
 
        ' attempt to access the database
        Try
            ' base connection chain
            Dim connectString As String = "DSN=" + dsnArticles + ";"
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()
 
            ' execution of a SQL command
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOdbcCommand As New OdbcCommand(sqlText)
            myOdbcCommand.Connection = articlesConn
            myReader = myOdbcCommand.ExecuteReader()
 
            ' Using the recovered table
            ' column display
            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))
 
            ' data display
            While myReader.Read()
                ' current line operation
                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
            ' drive lock
            myReader.Close()
            ' locking connection
            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=value1;param2=value2;...;paramj=valuej;". وفيما يلي بعض المعلمات المحتملة لـ paramj:

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

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


        ' preparing the connection to the comic
        Dim articlesConn As OdbcConnection = Nothing        ' the connection
        Dim myReader As OdbcDataReader = Nothing        ' the data reader
        Try
            ' attempt to access the database
            ' base connection chain
            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 connection): يتم تعيين المعلمة sqlText إلى الخاصية CommandText، والمعلمة connection إلى الخاصية Connection.

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

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

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


            ' exécution d'une commande 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
يمثل العنصر (i) العمود رقم i في الصف الحالي في النتيجة
XXX GetXXX(i)
قيمة العمود i للصف الحالي، يتم إرجاعها كنوع XXX (Int16، Int32، Int64، Double، String، Boolean، ...)
سلسلة GetName(i)
اسم العمود رقم i
Close()
يغلق كائن OdbcdataReader ويحرر الموارد المرتبطة به
bool Read()
يتقدم صفًا واحدًا في جدول النتائج. يُرجع false إذا كان ذلك غير ممكن. يصبح الصف الجديد هو الصف الحالي للقارئ.

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


While myReader.Read()
    ' on a une ligne - on l'exploite
    ....
    ' ligne suivante
end while

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


            ' Exploitation de la table récupérée
            ' affichage des colonnes
            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))
 
            ' affichage des données
            While myReader.Read()
                ' exploitation ligne courante
                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

يتم ترجمة الترميز line+=myReader(i).ToString إلى line+=myReader.Item(i).ToString()، حيث Item(i) هي قيمة العمود i في الصف الحالي.

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

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

                ' fermeture lecteur
                myReader.Close()
                ' fermeture connexion
                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=[file.mdb]. الجزء القابل للتكوين من هذه السلسلة هو اسم ملف ACCESS المراد استخدامه. سنقوم بتعديل برنامجنا بحيث يقبل اسم هذا الملف كمعلمة.
  • أصبح مساحة الاسم المطلوب استيرادها الآن هي System.Data.OleDb.

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


' options
Option Explicit On 
Option Strict On
 
' namespaces
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)
 
        ' application console
        ' displays the contents of a ARRTICLES table in a DSN database 
        ' whose name is passed in parameter
        Const syntaxe As String = "syntaxe : pg base_access_articles"
        Const tabArticles As String = "articles"        ' table of articles
 
        ' parameter verification
        ' do we have 1 parameter
        If args.Length <> 1 Then
            ' error msg
            Console.Error.WriteLine(syntaxe)
            ' end
            Environment.Exit(1)
        End If
 
        ' parameter is retrieved
        Dim dbArticles As String = args(0)        ' the database
 
        ' preparing the connection to the comic
        Dim articlesConn As OleDbConnection = Nothing        ' the connection
        Dim myReader As OleDbDataReader = Nothing        ' the data reader
 
        ' attempt to access the database
 
        Try
            ' base connection chain
            Dim connectString As String = "Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + dbArticles + ";"
            articlesConn = New OleDbConnection(connectString)
            articlesConn.Open()
 
            ' execution of a SQL command
            Dim sqlText As String = "select * from " + tabArticles
            Dim myOleDbCommand As New OleDbCommand(sqlText)
            myOleDbCommand.Connection = articlesConn
            myReader = myOleDbCommand.ExecuteReader()
 
            ' Using the recovered table
            ' column display
            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))
            ' data display
            While myReader.Read()
                ' current line operation
                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
            ' drive lock
                myReader.Close()
                ' locking connection
                articlesConn.Close()
        End Try
        ' end
        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

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


' options
Option Explicit On 
Option Strict On

' namespaces
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)
 
        ' application console
        ' executes SQL requests typed on the keyboard on a 
        ' table ARTICLES from a database DSN whose name is passed as a parameter
        Const syntaxe As String = "syntaxe : pg dsnArticles"
 
        ' parameter verification
        ' do we have 2 parameters
        If args.Length <> 1 Then
            ' error msg
            Console.Error.WriteLine(syntaxe)
            ' end
            Environment.Exit(1)
        End If        'if
        ' parameter is retrieved
        Dim dsnArticles As String = args(0)
        ' base connection chain
        Dim connectString As String = "DSN=" + dsnArticles + ";"
 
        ' preparing the connection to the comic
        Dim articlesConn As OdbcConnection = Nothing
        Dim sqlCommand As OdbcCommand = Nothing
        Try
            ' attempt to access the database
            articlesConn = New OdbcConnection(connectString)
            articlesConn.Open()
            ' create a command object
            sqlCommand = New OdbcCommand("", articlesConn)
            'try
        Catch ex As Exception
            ' error msg
            Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
            ' freeing up resources
            Try
                articlesConn.Close()
            Catch
            End Try
            Environment.Exit(2)
        End Try        'catch
        ' build a dictionary of accepted sql commands
        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
 
        ' read-execute SQL commands typed on the keyboard
        Dim requête As String = Nothing        ' query text SQL
        Dim champs() As String        ' query fields    
        Dim modèle As New Regex("\s+")
        ' input-execution loop for SQL commands typed on keyboard
        While True
            ' no error at start
            Dim erreur As Boolean = False
            ' request for query
            Console.Out.Write(ControlChars.Lf + "Requête SQL (fin pour arrêter) : ")
            requête = Console.In.ReadLine().Trim().ToLower()
            ' finished?
            If requête = "fin" Then
                Exit While
            End If
            ' the query is broken down into fields
            champs = modèle.Split(requête)
            ' valid request?
            If champs.Length = 0 Or Not dicoCommandes.ContainsKey(champs(0)) Then
                ' error msg
                Console.Error.WriteLine("Requête invalide. Utilisez select, insert, update, delete")
                ' following request
                erreur = True
            End If
            If Not erreur Then
                ' prepare the Command object to execute the request
                sqlCommand.CommandText = requête
                ' query execution
                Try
                    If champs(0) = "select" Then
                        executeSelect(sqlCommand)
                    Else
                        executeUpdate(sqlCommand)
                    End If
                Catch ex As Exception
                    ' error msg
                    Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
                End Try
            End If
        End While
        ' freeing up resources
        Try
            articlesConn.Close()
        Catch
        End Try
        Environment.Exit(0)
    End Sub
 
    ' execute an update request
    Sub executeUpdate(ByVal sqlCommand As OdbcCommand)
        ' executes sqlCommand, update request
        Dim nbLignes As Integer = sqlCommand.ExecuteNonQuery()
        ' display
        Console.Out.WriteLine(("Il y a eu " & nbLignes & " ligne(s) modifiée(s)"))
    End Sub
 
    ' executing a Select query
    Sub executeSelect(ByVal sqlCommand As OdbcCommand)
        ' executes sqlCommand, select query
        Dim myReader As OdbcDataReader = sqlCommand.ExecuteReader()
        ' Using the recovered table
        ' column display
        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))
        ' data display
        While myReader.Read()
            ' current line operation
            ligne = ""
            For i = 0 To myReader.FieldCount - 1
                ligne += myReader(i).ToString + " "
            Next i
            ' display
            Console.WriteLine(ligne)
        End While
        ' freeing up resources
        myReader.Close()
    End Sub
End Module

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

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

        ' on construit un dictionnaire des commandes sql acceptées
        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

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


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

        Dim modèle As New Regex("\s+")
....
            ' the query is broken down into fields
            champs = modèle.Split(requête)

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

  • لا يستخدم تنفيذ استعلام SELECT نفس الطريقة المستخدمة في تنفيذ استعلام التحديث (INSERT، UPDATE، DELETE). لذلك، يجب إجراء فحص وتنفيذ وظيفة مختلفة لكل من هاتين الحالتين:

                ' préparation de l'objet Command pour exécuter la requête
                sqlCommand.CommandText = requête
                ' exécution de la requête
                Try
                    If champs(0) = "select" Then
                        executeSelect(sqlCommand)
                    Else
                        executeUpdate(sqlCommand)
                    End If                    'try
                Catch ex As Exception
                    ' msg d'erreur
                    Console.Error.WriteLine(("Erreur d'exploitation de la base de données (" + ex.Message + ")"))
                End Try

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

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

7.3.5. حساب الضريبة

نعيد استخدام كائن الضريبة الذي تم إنشاؤه في فصل سابق:


' options
Option Strict On
Option Explicit On 
 
' namespaces
Imports System
 
Public Class impôt
    ' data required for tax calculation
    ' come from an external source
    Private limites(), coeffR(), coeffN() As Decimal
 
    ' manufacturer
    Public Sub New(ByVal LIMITES() As Decimal, ByVal COEFFR() As Decimal, ByVal COEFFN() As Decimal)
        ' we check that the 3 tablaeux are the same size
        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
        ' it's good
        Me.limites = LIMITES
        Me.coeffR = COEFFR
        Me.coeffN = COEFFN
    End Sub
 
    ' tAX CALCULATION
    Public Function calculer(ByVal marié As Boolean, ByVal nbEnfants As Integer, ByVal salaire As Integer) As Long
        ' calculating the number of shares
        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
        ' calculation of taxable income & family quota
        Dim revenu As Decimal = 0.72D * salaire
        Dim QF As Decimal = revenu / nbParts
        ' tAX CALCULATION
        limites((limites.Length - 1)) = QF + 1
        Dim i As Integer = 0
        While QF > limites(i)
            i += 1
        End While
        ' return result
        Return CLng(revenu * coeffR(i) - nbParts * coeffN(i))
    End Function
End Class

نضيف مُنشئًا جديدًا لتهيئة مصفوفات limit و coeffR و coeffN من قاعدة بيانات ODBC:


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

    ' builder 2
    Public Sub New(ByVal DSNimpots As String, ByVal Timpots As String, ByVal colLimites As String, ByVal colCoeffR As String, ByVal colCoeffN As String)
        ' initializes the three limit arrays, coeffR, coeffN from
        ' the contents of the Timpots table in the ODBC DSNimpots database
        ' colLimites, colCoeffR, colCoeffN are the three columns of this table
        ' can throw an exception
        Dim connectString As String = "DSN=" + DSNimpots + ";"        ' base connection chain
        Dim impotsConn As OdbcConnection = Nothing        ' the connection
        Dim sqlCommand As OdbcCommand = Nothing        ' the SQL command
        ' the SELECT query
        Dim selectCommand As String = "select " + colLimites + "," + colCoeffR + "," + colCoeffN + " from " + Timpots
        ' tables to retrieve data
        Dim tLimites As New ArrayList
        Dim tCoeffR As New ArrayList
        Dim tCoeffN As New ArrayList
 
        ' attempt to access the database
        impotsConn = New OdbcConnection(connectString)
        impotsConn.Open()
        ' create a command object
        sqlCommand = New OdbcCommand(selectCommand, impotsConn)
        ' execute the query
        Dim myReader As OdbcDataReader = sqlCommand.ExecuteReader()
        ' Using the recovered table
        While myReader.Read()
            ' the data of the current line are put in the tables
            tLimites.Add(myReader(colLimites))
            tCoeffR.Add(myReader(colCoeffR))
            tCoeffN.Add(myReader(colCoeffN))
        End While
        ' freeing up resources
        myReader.Close()
        impotsConn.Close()
 
        ' dynamic tables are placed in static tables
        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

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


Option Explicit On 
Option Strict On
 
' namespaces
Imports System
Imports Microsoft.VisualBasic
 
' test pg
Module testimpots
    Sub Main(ByVal arguments() As String)
        ' interactive tax calculator
        ' the user enters three data points on the keyboard: married nbEnfants salary
        ' the program then displays the tax payable
        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"
 
        ' checking program parameters
        If arguments.Length <> 5 Then
            ' error msg
            Console.Error.WriteLine(syntaxe1)
            ' end
            Environment.Exit(1)
        End If        'if
        ' retrieve the arguments
        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)
 
        ' tax object creation
        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
 
        ' infinite loop
        While True
            ' initially no errors
            Dim erreur As Boolean = False
 
            ' tax calculation parameters are requested
            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()
 
            ' anything to do?
            If paramètres Is Nothing Or paramètres = "" Then
                Exit While
            End If
 
            ' check the number of arguments in the input line
            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
                ' checking parameter validity
                ' married
                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
                ' salary
                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
                ' parameters are correct - tax is calculated
                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-imports:

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 :