28-01-14, 04:14 PM
السلام عليكم ورحمة الله
اليوم، سأكتب عن الـDataTable، وأتمنى لكم الفائدة..
الكلاس DataTable
ويمثل جدولاً واحداً ضمن الـDataSet. وكل جدول لا بد أن تتوفر فيه الكلاسات: DataColumn وDataRow، فللجدول حقول (أعمدة Columns) وسجلات (صفوف Rows). وهذا الكلاس يتبع مباشرة لفضاء الأسماء System.Data.
إنشاء جدول Creating a DataTable
هذا الكلاس يتبع مباشرة لفضاء الأسماء System.Data، ولإنشاء جدول نقوم بتعريف كائن DataTable، وبشكل اختياري يمكننا منحه اسماً:
في السطر السابق تم تعريف كائن يمثل جدولاً دون أن نسميه، وفي السطر التالي، نقوم بتعريف كائن يمثل جدولاً باسم Customers:
• إذا لم نحدد اسماً للجدول، يقوم ADO.NET بتسميته Table1، والجدول الذي يليه Table2 وهكذا.
• بعد إنشاء كائن الجدول، يمكننا تعديل قيمة الخاصية TableName لإعطائه اسماً أو تعديله، كما يمكننا التعامل مع بقية الخصائص والوظائف والأحداث.
إضافة DataTable إلى DatatSet
يضاف الجدول DataTable المنشأ حديثاً إلى الـDataSet بالصورة التالية:
وذلك من خلال الوظيفة Add التابعة للخاصية Tables التابعة للـDataSet.
أهم خصائص DataTable:
الخاصية TableName: ومن خلالها يمكن ضبط / استرجاع اسم الـDataTable.
الخاصية Columns: ومن خلالها يمكن استرجاع تجمع الأعمدة أو الحقول التابعة للـDataTable.
وستتضح الصورة أكثر بعد الحديث عن كل من : DataColumn و DataRow.
الخاصية DataSet: ومن خلالها يمكن استرجاع الـDataSet التي يتبعها هذا الـDataTable.
الخاصية PrimaryKey: ومن خلالها يمكن ضبط / استرجاع مصفوفة من الأعمدة أو الحقول التي تعمل كمفاتيح أساسية للـDataTable. وسأشرح عنها عند الحديث عن DataColumn.
الخاصية Rows: ومن خلالها يمكن استرجاع تجمع الصفوف التي تتبع هذا الـDataTable. وسأشرح عنها عند الحديث عن DataRow.
أهم وظائف DataTable:
الوظيفة Clear: وتقوم بمسح محتويات الجدول من البيانات فقط، ولا تحذف تركيبته.
الوظيفة Clone: وتقوم بنسخ تركيبة الجدول دون البيانات.
الوظيفة Copy: وتقوم بنسخ تركيبة ومحتويات الجدول إلى جدول آخر .
الوظيفة ImportRow: وتقوم بنسخ DataRow إلى جدول DataTable مع الاحتفاظ بإعداداته السابقة والقيم التي يحملها. وسأشرح عنها عند الحديث عن DataRow.
الوظيفة Merge(DataTable): وتقوم بدمج الجدول المعطى مع الجدول الحالي. سأشرحها لاحقاً في استعراض العمليات على الجداول.
الوظيفة Merge(DataTable, Boolean): وتقوم بدمج الجدول المعطى مع الجدول الحالي مع إعطاء الإمكانية لحفظ التغييرات من عدمه.
الوظيفة NewRow: وتقوم بإنشاء DataRow بنفس تركيبة الجدول. بحيث تراعى أنواع البيانات وأحجامها وإعداداتها لكل عمود.
الوظيفة Reset: وتقوم بإعادة ضبط الجدول إلى حالته القديمة. وحذف كافة البيانات المخزنة فيه، بالإضافة إلى الفهارس والعلاقات والأعمدة.
الوظيفة Select: وتقوم باسترجاع مصفوفة تمثل كافة الـDataRows بالجدول.
ويمكن الوصول إلى كل صف في هذه المصفوفة من خلال الـIndex:
الوظيفة Select(String): وتقوم باسترجاع مصفوفة تمثل الـDataRows التي تخضع للمعايير المحددة.
الوظيفة Select(String, String): وتقوم باسترجاع مصفوفة تمثل الـDataRows التي تخضع للمعايير المحددة بترتيب محدد.
إضافة أعمدة (حقول) للجدول Adding Columns to DataTable
الحمد لله، وصلنا إلى الجزء المثير والممتع! إذ أنه بعد تعريف الكائن الذي يمثل DataTable، سيكون ذلك الكائن فارغاً، وبالتالي لا نستفيد منه شيئاً! والخطوة القادمة هي بالتأكيد إنشاء الحقول أو Data Columns.
يحتوي فضاء الأسماء System.Data أيضاً على كلاس يسمى DataColumn والذي يمثل حقلاً واحداً في تركيبة الجدول Table Schema.
ولإضافة حقل إلى الجدول، نقوم بتعريف كائن يمثل الجدول:
ثم نعرف كائناً آخر يمثل الحقل، وأنبه هنا إلى أن الحد الأدنى لتعريف الحقل هو توفير اسم الحقل ونوع البيانات التي يحملها:
ففي السطر السابق، تم تعريف الكائن CustomerID على أنه كائن يمثل حقلاً اسمه ID ونوع بياناته Long.
بقيت خطوة أخيرة، وهي ضم الكائن الجديد للجدول:
وفي السطر السابق، تم استخدام الوظيفة Add التابعة لتجمع الحقول Columns لإضافة الحقل الجديد إلى الجدول. ونفعل ذلك لكل عمود جديد. أو بطريقة أخرى، وهي باستخدام الوظيفة Add التابعة لتجمع الحقول Columns لإضافة حقول جديدة دون تعريف كائنات تمثل كل الحقول:
خصائص الكلاس DataColumn
الكود السابق يوضح طريقة إنشاء الحقول بأبسط الطرق، وبالحد الأدنى من المعلومات المتعلقة بالحقول. ولكن هناك الكثير من الخصائص الأخرى التي تجعل من إنشاء الحقول وضمها للجدول أكثر احترافية وإتقاناً، أذكر منها على سبيل المثال:
الخاصية AllowDBNull: وتحمل قيمة منطقية Boolean، وتحدد ما إذا كان من المسموح أن لا يحمل هذا الحقل أية قيمة، أي قيمته = Null.
أو
ويمكن استعمال الكلاس System.DBNull لاختبار القيمة قبل تخزينها لاحقاً في هذا الحقل (تلقائياً: كل الحقول تسمح بالقيمة Null):
وكذلك توجد دالة في فجول بيسك وظيفتها فحص قيم المتغيرات:
الخصائص AutoIncrement، وAutoIncrementSeed وAutoIncrementStep: تدير هذه الخصائص عملية الزيادة التلقائية لقيم الحقول التي تحمل هذه الميزة، فعند تطبيقها، يتم زيادة القيم تلقائياً عند إضافة سجلات جديدة بمقادير تتحدد من خلال الخاصيتين AutoIncrementSeed وAutoIncrementStep. وبشكل تلقائي فإن الخاصية AutoIncrement مضبوطة على الوضع False، وبالتالي فإن هذه الآلية لا تعمل.
الخاصية ColumnName: وهي خاصية نصية تمثل اسم الحقل. ويتم تحديدها وضبطها وقت إنشاء الحقل.
الخاصية DataType: وتمثل نوع البيانات التي سيحملها الحقل. ويتم تحديدها وضبطها وقت إنشاء الحقل، وإذا ما تم إضافة البيانات، لا يمكن تعديل نوعها.
الخاصية DefaultValue: وتمثل القيمة الافتراضية للحقل، ويمكن لأي حقل أن يحمل قيمة افتراضية، ويتم تخزين هذه القيمة كلما تم إنشاء سجل جديد، ويمكن تعديلها لاحقاً دون أية مشكلة.
الخاصية MaxLength: وهي خاصة بالحقول التي تحمل قيماً نصية، وتحدد طول النص الذي سيحمله هذا الحقل، وتلقائياً: قيمته هي -1، بمعنى أنه لا حد لطول النص.
الخاصية ReadOnly: حقول القراءة فقط لا يمكن تعديل قيمها في أي سجل قد تمت إضافته فعلاً للجدول، وتلقائياً: جميع قيم الحقول قابلة للتعديل.
الخاصية Unique: وهي خاصية منطقية، إذا ضبطت بالقيمة True، فإن الحقل لا يسمح بحمل قيمتين متساويتين، وكذلك في هذا النوع من الحقول لا يمكن تخزين قيمة Null.
وهناك خاصية تتبع الكلاس DataTable وهي PrimaryKey، ومن خلالها – كما أسلفت - يمكن ضبط / استرجاع مصفوفة من الأعمدة أو الحقول والتي تعمل كمفاتيح أساسية للـDataTable:
عند إضافة DataColumn للجدول DataTable، يتم إضافته إلى ما يعرف بـColumns Collection أو تجمع الأعمدة (الحقول). هذه الحقول لا تحمل أية قيم إلى حد الآن، وإنما يتم إضافة البيانات عن طريق ما يعرف بـRows Collection أو تجمع الصفوف والذي يتبع الكائن DataTable كما سنرى لاحقاً إن شاء الله.
إنشاء صفوف جديدة Creating New Rows
إن عملية إنشاء الجداول Creating DataTables وأعمدتها DataColumns هي عملية أساسية قبل المضي قدماً للخطوة اللاحقة وهي: عملية إضافة البيانات للجدول أو "إنشاء سجلات (صفوف Rows) جديدة".
وكما تعلمنا سابقاً، فإننا إذ ننشئ الأعمدة (الحقول DataColumns) إنما ننشئ قوالب لا نهائية من حيث العدد، يمكننا حفظ البيانات فيها بالصورة التي نريد. والآن، أود أن أحدثكم عن الكلاس DataRow..
الكلاس DataRow
ويمثل صفاً كاملاً من الـDataColumns التي يتكون منها الـDataTables. آخذاً في الاعتبار نوع وحجم كل عمود DataColumn في الجدول.
أهم خصائص الكلاس DataRow
الخاصية Item(DataColumn): ومن خلالها يتم ضبط / استرجاع القيمة المخزنة بحقل محدد.
الخاصية Item(Int32): ومن خلالها يتم ضبط / استرجاع القيمة المخزنة بحقل محدد بدلالة رقم فهرسه.
الخاصية Item(String): ومن خلالها يتم ضبط / استرجاع القيمة المخزنة بحقل محدد بدلالة اسمه.
الخاصية Table: ومن خلالها يتم استرجاع اسم الجدول DataTable الذي ينتمي إليه الصف.
أهم وأشهر وظائف DataRow:
الوظيفة Delete: وتقوم بحذف الـDataRow.
وكما تلاحظون في الكود، فإنني استعملت الوظيفة AcceptChanges لتأكيد الحذف. وسنتطرق لها في معالجة الحزم لاحقاً إن شاء الله.
الوظيفة IsNull(DataColumn): وتحدد ما إذا كانت القيمة التي يحملها الـDataColumn هي Null.
الوظيفة IsNull(Int32): وتحدد ما إذا كانت القيمة التي يحملها الـDataColumn (بدلالة فهرسه) هي Null.
يدعم الكلاس DataTable الطريقة NewRow لتوليد صف جديد يخضع لإعدادات الـDataColumns، من حيث نوع الحقل وطوله وخصائصه الأخرى وذلك لكل حقل من الحقول التي يحتوي عليها DataTable.
ولفتح صف (سجل DataRow) جديد في الجدول:
بعد تنفيذ السطر البرمجي السابق، يتم وبشكل تلقائي إنشاء صف بيانات جديد بحيث يراعى فيه خصائص كل حقل، ويتم وضع القيمة Null في كافة الحقول، عدا تلك التي لها قيم افتراضية Default Values، أو التي خاصية AutoIncrement لها = True.
هناك المزيد من هذه الوظائف، سأتطرق لها لاحقاً مثل الوظيفة SetAdded وSetModified.
ضبط قيم الحقول في الـDataRow الجديد
يتضمن الكلاس DataRow خاصية مهمة وهي Item، والتي تعطي إمكانية الوصول إلى كل DataColumn معرّف في الـDataTable اعتماداً على اسم الحقل أو رقم ترتيبه (ابتداء من الصفر) أو متغير يمثل الـDataColumn، و السنّة المتبعة هي الاعتماد على اسم الحقل تجنباً لأخطاء غير مقصودة، وتوضيحاً للكود، مع الأخذ في الاعتبار خصائص كل حقل على حدة.
في الكود السابق تم ضبط قيمة أول حقل في الجدول (ID) من خلال اسم الحقل مرة، ورقم ترتيبه مرة ، ومن خلال مرجع يمثل الحقل المطلوب مرة ثالثة.
الخاصية Item هي الخاصية التلقائية للكلاس DataRow، ولذلك يمكن الاستغناء عن ذكرها وكتابة:
كما يمكن استعمال علامة التعجب (!) لتشير إلى اسم الحقل (لا تدعم رقم فهرس الحقل) في الجدول:
حفظ البيانات في الجدول DataTable
بعد ضبط وتعيين القيم في السجل الجديد، تكون الخطوة اللاحقة هي ضم هذا السجل إلى الجدول DataTable، مستعملين الطريقة .Rows.Add التابعة للـDataTable:
كما يمكن استعمال طريقة أخرى، وهي بتنفيذ الطريقة Rows.Add وإرسال قيم الحقول كبارامترات:
وأي طريقة اخترنا، فإن الوظيفة Add تختبر القيم المرسلة من حيث توافقها مع تركيبة الجدول وحقوله، وترفض القيم التي لا تتماشى مع القواعد.
الوصول إلى الصف المطلوب في جدول DataTable
أو بصيغة أخرى، طريقة تحديد صف معين أو مجموعة من الصفوف في جدول لإجراء عمليات عليها. وتوجد عدة طرق لاسترجاع الصفوف المطلوبة منها:
أ) استرجاع الصفوف بدلالة قيم الأعمدة
وذلك باستخدام الوظيفة Select Method، التابعة للـDataTable
ففي هذا الكود تم تعريف مصفوفة لتجمع بداخلها الصفوف المسترجعة من عملية البحث باستخدام الطريقة Select، والتي مررنا لها قيمة الحقل LastName. فإن تم العثور على السجلات المطلوبة فإنها تخزن في تلك المصفوفة.
ويمكن معرفة عدد الصفوف المسترجعة من خلال الكود التالي:
ويمكن الوصول إلى حقول كل صف بالكيفية التالية:
ب) استرجاع الصفوف بدلالة قيمة الحقل المفتاحي Primary Key Value
وفي هذه الحالة نستخدم الطريقة Find التابعة للتجمع DataRowCollection ونرسل لها القيمة المفتاحية كبارامتر:
تعديل البيانات في الجدول DataTable
لتعديل بيانات أي صف في جدول DataTable، يلزمنا كبداية تحديد الصف المطلوب تعديل بياناته، ومن ثم إسناد القيم المناسبة لكل حقل من حقوله.
ولمعرفة الصف المطلوب تعديله، نستخدم الطريقة Select Method التابعة للـDataTable بالصورة التالية:
ففي الكود السابق، الحقل CustomerID هو الحقل المفتاحي للجدول Primary Key، وبالتالي عند استخدام الطريقة Select وتمرير رقم الزبون فإن النتيجة هي إرجاع مصفوفة customerRow() تحتوي على صف واحد فقط، إذ أن رقم الزبون لا يتكرر. ثم استعملنا الرقم (0) للتعبير عن أول صف مسترجع في المصفوفة، وعدلنا قيم الحقول المقصودة.
بالإمكان تعديل الكود السابق والخاص بضبط القيم إلى:
ولكن كما قلتُ سابقاً أن الخاصية Item هي الخاصية التلقائية للكلاس DataRow، ولذلك يمكن الاستغناء عن ذكرها.
وفي حالة أننا نعلم رقم ترتيب الصف المطلوب تعديله، بدلالة رقم الجدول في الـDataSet نكتب:
أو بدلالة اسم الجدول:
عرض بيانات الجدول Viewing Data in a DataTable
يمكننا الوصول لبيانات الجدول من خلال استعمال التجمعات Rows وColumns الخاصة بالـDataTable. وكذلك استعمال الطريقة Select Method لاسترجاع مجموعة من السجلات التي تخضع لشروط معينة وترتيب معين وحالة صف معينة.
بالإضافة إلى استعمال الطريقة Find Method التابعة للتجمع DataRowCollection للبحث عن سجل معين عن طريق مفتاحه الأساسي.
استعمال الطريقة Select Method يرجع مجموعة من كائنات الـDataRow ، تنطبق عليها شروطنا، وتقبل بارامترات تمثل:
• صيغة الفرز (الشروط) Filter expression.
• طريقة الترتيب Sort expression.
• حالة كل صف DataViewRowState.
صيغة الفرز تحدد الصفوف المسترجعة بناء على قيم الحقول DataColumn مثلاً LastName = “Swedan”.
وطريقة الترتيب تحدد من خلال جملة Sql مثلاً ORDER BY LastName DESC.
أما حالة كل صف فسنتعرف عليها لاحقاً إن شاء الله في موضوع: حالة الصف Row State.
حذف البيانات من جدول Removing Data from DataTable
يمكن حذف الصفوف من الجدول DataTable باستخدام:
• الطريقة Remove التابعة للتجمع DataTable.Rows.
• الطريقة RemoveAt التابعة للتجمع DataTable.Rows.
والطريقة Remove Method تأخذ متغيراً يمثل صفاً في الجدول:
أما الطريقة RemoveAt Method فتأخذ رقم فهرس الصف مباشرة:
وكل الطرق تؤدي إلى مكة.
ويمكن حذف جميع الصفوف بأمر واحد، وذلك باستخدام الطريقة Clear Method التابعة للكائن DataTable.Rows:
ويجب ملاحظة أنه عند حذف الصفوف بهذه الطريقة، فإنه لا يمكننا التراجع عن عملية الحذف إطلاقاً، وهذا ما سنفهمه من الموضوع التالي.
معالجة الحزم / الدفعات Batch Processing
جميع العمليات التي قمنا بها سابقاً هي عمليات مباشرة تتم على سجلات الجدول وحقوله، الأمر للوهلة الأولى جيد ورائع، ولكن لهذا النظام عيوب منها عدم القدرة على استرجاع قيم سابقة للحقول، ولا يمكن التراجع عن أي عملية والرجوع إلى الحالة السابقة.
ADO.NET يوفر مزايا جديدة بحيث يمكننا عمل تغييرات على عدة سجلات، وبعدها نقرر هل نطبق هذه التغييرات أم نتجاهلها! وهذه الطريقة تسمى: معالجة الحزم أو الدفعات.
وللاستفادة من هذه الطريقة في المعالجة، ببساطة نقوم بإحداث التغييرات التي نريد، وعندما نكون جاهزين لتطبيق هذه التغيرات:
• نستخدم الطريقة AcceptChanges Method التابعة للـDataTable ليتم تطبيق التغييرات وتحديث بيانات الجدول.
• أو نستخدم الطريقة RejectChanges Method لرفض التغييرات غير المحفوظة والحفاظ على بيانات الجدول كما هي دون تغيير.
يمكن تطبيق هاتين الطريقتين حتى على الـDataRows. فكل DataRow يدعم هاتين الطريقتين، ولكن استخدام AcceptChanges أو RejectChanges على الجدول بأكمله أفضل من استعمالهما مع كل صف على حدة، لأنه سيتم الدوران على كافة الصفوف التي حدث بها التغيير وتطبيقها (في حال استعمال AcceptChanges) أو رفض التغييرات (في حال استعمال RejectChanges).
حالة الصف Row State
في أثناء إجراء التغييرات على الصف، يقوم ADO.NET بحفظ النسخة الأصلية والنسخة المعدلة لكافة الحقول التي يحتويها هذا الصف، وكذلك بمراقبة وتحديد الصفوف المضافة و/أو المحذوفة من الجدول، بحيث يمكن أن نعود للنسخة الأصلية حين الحاجة. يفعل ADO.NET كل ذلك من خلال حفظ حالة كل حقل لكل الصفوف ويتم تحديث قيمة الخاصية DataRow.RowState لكل صف على حدة، والتي تحتمل إحدى القيم التالية:
• DataRowState.Detached: وهي الحالة الافتراضية لأي صف لم يتم إضافته بعد إلى DataTable.
• DataRowState.Added: وهي حالة كل صف تم إضافته إلى DataTable ولكن لم تأكيد الإضافة. بحيث لو استعملنا RejectChanges يتم حذفها فوراً.
• DataRowState.UnChanged: وهي الحالة الافتراضية لأي صف موجود مسبقاً بالجدول ولم تتم عليه أي عملية تعديل منذ آخر مرة تم فيها استدعاء الطريقة AcceptChanges Method. وهي الحالة الافتراضية أيضاً لكافة السجلات التي تم إنشاؤها من خلال الطريقة NewRow.
• DataRowState.Deleted: الصفوف المحذوفة لا يتم إزالتها فعلياً من الجدول إلى أن يتم استدعاء الطريقة AcceptChanges، بل يتم تأشيرها على أنها ستحذف من خلال هذه الخاصية.
• DataRowState.Modified: أي صف تم تعديل حقوله بأي طريقة يؤشر على أنه Modified.
ففي كل مرة نقوم بإضافة أو تعديل صف، يتم تحديث حالته فوراً، على عكس عملية الحذف من خلال Rows.Remove و Rows.RemoveAt، فإنه يحدث التفاف حول نظام تتبع حالات السجلات هذا، ولا يتم تحديث الحالة على نفس المنوال، لأنه يتم حذف الصفوف مباشرة، ولا يجعلها تخضع لنظام معالجة الحزم.
ولحل هذه المشكلة، نستعمل الطريقة Delete Method التابعة للـDataRow عوضاً عن Rows.Remove و/أو Rows.RemoveAt، فهي لا تقوم بحذف الصفوف، بل بتغيير حالتها إلى Deleted، وبالتالي نستطيع تأكيد الحذف من خلال الطريقة AcceptChanges، أو التراجع عن الحذف من خلال RejectChanges.
عند استدعاء الطريقة AcceptChanges سواء من خلال DataSet أو DataTable أو DataRow فإن يتم حذف كافة السجلات التي حالتها = Deleted، وتطبيق التعديلات التي حصلت على السجلات الأخرى بحيث تحل القيم الجديدة Current Values محل القيم الأصلية Original Values.
أما عند استدعاء الطريقة RejectChanges، فإنه يتم حذف كافة السجلات التي حالتها = Added، وتعطى باقي السجلات الحالة Unchanged، وتلغى التعديلات التي حصلت على السجلات الأخرى بحيث تحل القيم الأصلية Original Values محل القيم الجديدة Current Values.
وظائف أخرى للـDataRow
هناك بعض الوظائف الإضافية التي لم أذكرها عند حديثي عن الـDataRow ، مهمة تلك الوظائف هي ضبط حالة الصف مثل:
الوظيفة SetAdded: تقوم بتغيير الـDataState للـDataRow إلى Added.
الوظيفة SetModified: تقوم بتغيير الـDataState للـDataRow إلى Modified.
نُسخ الصف Row Versions
عند إجراء التعديلات والتغييرات سواء إضافة أو حذف أو تعديل في بيانات الصفوف، فإن ADO.NET يحتفظ بنسخ متعددة لكل صف حتى ولو تم تغيير قيمة حقل واحد فقط.
DataRowVersion
ويحتمل إحدى القيم التالية:
• DataRowVersion.Original: يعني الاحتفاظ بالقيم الأصلية للحقول منذ آخر استدعاء للطريقة AcceptChanges، ولا يشمل الصفوف الجديدة.
• DataRowVersion.Porposed: يعني أن قيمة حقل ما تغيرت، ولكن لم يتم تأكيد التغيير. هذه النسخة لا تتوفر حتى يتم البدء في عملية تعديل قيمة الحقل. بعد تأكيد التغييرات، تتحول القيمة إلى Original.
• DataRowVersion.Current: يعني أن التعديل جارٍ الآن، وعند تأكيده، تتحول القيمة إلى Original.
• DataRowVersion.Default: يعني النسخة التلقائية للصف. فالنسخة التلقائية للـ Added وModified وUnchanged هي Current، والنسخة التلقائية للـDeleted هي Original، والنسخة التلقائية للـDetached هي Proposed.
حيث Added وModified وUnchanged وDeleted و Detached هي حالات الصفوف.
فحص التغييرات الطارئة على محتويات جدول
قلتُ سابقاً أنه عند استعمال نظام معالجة الحزم، وفي حال حدث تغيير في الجدول، لا يتم تطبيق التعديلات إلا عند استدعاء الطريقة AcceptChanges Method. وبالتالي فالتغييرات تبقى معلقة pending حتى تطبيقها أو تجاهلها وإرجاع الجدول إلى سابق عهده (إلى حالته عند استدعاء AcceptChanges آخر مرة). وقلتُ أن عملية تتبع الصفوف تتم عن طريق:
• كل صف يحتوي على "RowState" وهي إحدى الحالات: Detached وAdded وModified وDeleted وUnchanged.
• كل صف تم تغيير محتوياته يتضمن نُسخاً مختلفة للصفوف: Original وProposed وCurrent وDefault.
معرفة ما إذا كان هناك تغيير في الصفوف
هناك طريقة Method تتبع الـDataSet هي: HasChanges، ذات قيمة منطقية، إذا ساوت True فإن هناك تغيير حدث على بعض الصفوف أو كلها. وفي تلك الحالة يمكن استدعاء الطريقة GetChanges التابعة للـDataSet و/أو للـDataTable لاسترجاع مصفوفة تحتوي على الصفوف المتغيرة، وهذه المصفوفة هي بمثابة DataSet أو DataTable مملوء بالصفوف المتغيرة فقط. ومن نافلة القول أنه يجب استدعاء الطريقة GetChanges قبل تطبيق التغييرات باستخدام الطريقة AcceptChanges، وإلا فلن نتحصل على أي صف!.
أ) استرجاع الصفوف المتغيرة من DataSet
وهنا نقوم بإنشاء DataSet وملئها بالصفوف المتغيرة:
ب) استرجاع الصفوف المتغيرة من DataTable
وهنا نقوم بإنشاء DataTable وملئه بالصفوف المتغيرة:
ج) استرجاع الصفوف المتغيرة بحسب نوعية التغيير (النسخة)
وهنا نرسل نوع الإصدارة إلى الطريقة GetChanges كبارامتر:
---------------
اليوم، سأكتب عن الـDataTable، وأتمنى لكم الفائدة..
الكلاس DataTable
ويمثل جدولاً واحداً ضمن الـDataSet. وكل جدول لا بد أن تتوفر فيه الكلاسات: DataColumn وDataRow، فللجدول حقول (أعمدة Columns) وسجلات (صفوف Rows). وهذا الكلاس يتبع مباشرة لفضاء الأسماء System.Data.
إنشاء جدول Creating a DataTable
هذا الكلاس يتبع مباشرة لفضاء الأسماء System.Data، ولإنشاء جدول نقوم بتعريف كائن DataTable، وبشكل اختياري يمكننا منحه اسماً:
كود :
Dim UnNamedTable As New DataTable
في السطر السابق تم تعريف كائن يمثل جدولاً دون أن نسميه، وفي السطر التالي، نقوم بتعريف كائن يمثل جدولاً باسم Customers:
PHP كود :
Dim Customers As New DataTable("Customers")
• إذا لم نحدد اسماً للجدول، يقوم ADO.NET بتسميته Table1، والجدول الذي يليه Table2 وهكذا.
• بعد إنشاء كائن الجدول، يمكننا تعديل قيمة الخاصية TableName لإعطائه اسماً أو تعديله، كما يمكننا التعامل مع بقية الخصائص والوظائف والأحداث.
إضافة DataTable إلى DatatSet
يضاف الجدول DataTable المنشأ حديثاً إلى الـDataSet بالصورة التالية:
PHP كود :
Dim EmployeesDataSet As New DataSet("Employees DataSet")
Dim PersonalInfoTable As New DataTable
EmployeesDataSet.Tables.Add(PersonalInfoTable)
وذلك من خلال الوظيفة Add التابعة للخاصية Tables التابعة للـDataSet.
أهم خصائص DataTable:
الخاصية TableName: ومن خلالها يمكن ضبط / استرجاع اسم الـDataTable.
PHP كود :
Dim FirstTable As New DataTable
MsgBox(FirstTable.TableName)
FirstTable.TableName = "Nationalities"
MsgBox(FirstTable.TableName)
الخاصية Columns: ومن خلالها يمكن استرجاع تجمع الأعمدة أو الحقول التابعة للـDataTable.
PHP كود :
Private Sub PrintValues(ByVal table As DataTable)
Dim row As DataRow
Dim column As DataColumn
For Each row in table.Rows
For Each column In table.Columns
Msgbox(row(column))
Next
Next
End Sub
الخاصية DataSet: ومن خلالها يمكن استرجاع الـDataSet التي يتبعها هذا الـDataTable.
PHP كود :
Dim EmployeesDataSet As New DataSet("Employees DataSet")
Dim PersonalInfoTable As New DataTable("Personal Info")
EmployeesDataSet.Tables.Add(PersonalInfoTable)
MsgBox(PersonalInfoTable.DataSet.DataSetName)
الخاصية PrimaryKey: ومن خلالها يمكن ضبط / استرجاع مصفوفة من الأعمدة أو الحقول التي تعمل كمفاتيح أساسية للـDataTable. وسأشرح عنها عند الحديث عن DataColumn.
الخاصية Rows: ومن خلالها يمكن استرجاع تجمع الصفوف التي تتبع هذا الـDataTable. وسأشرح عنها عند الحديث عن DataRow.
أهم وظائف DataTable:
الوظيفة Clear: وتقوم بمسح محتويات الجدول من البيانات فقط، ولا تحذف تركيبته.
PHP كود :
PersonalInfoTable.Clear()
الوظيفة Clone: وتقوم بنسخ تركيبة الجدول دون البيانات.
PHP كود :
Dim PersonalInfoTable As New DataTable
PersonalInfoTable.TableName = "Original Table"
Dim ClonedTable As New DataTable
ClonedTable = PersonalInfoTable.Clone()
MsgBox(ClonedTable.TableName)
الوظيفة Copy: وتقوم بنسخ تركيبة ومحتويات الجدول إلى جدول آخر .
PHP كود :
Dim PersonalInfoTable As New DataTable
PersonalInfoTable.TableName = "Original Table"
Dim CopiedTable As New DataTable
CopiedTable = PersonalInfoTable.Copy()
MsgBox(CopiedTable.TableName)
الوظيفة ImportRow: وتقوم بنسخ DataRow إلى جدول DataTable مع الاحتفاظ بإعداداته السابقة والقيم التي يحملها. وسأشرح عنها عند الحديث عن DataRow.
PHP كود :
Dim tblItems As New DataTable("Items")
Dim column As New DataColumn("id", GetType(System.Int32))
column.AutoIncrement = True
tblItems.Columns.Add(column)
column = New DataColumn("item", GetType(System.String))
tblItems.Columns.Add(column)
tblItems.PrimaryKey = New DataColumn() {tblItems.Columns(0)}
Dim NewRow As DataRow
NewRow = tblItems.NewRow
With NewRow
.Item("id") = 1
.Item("item") = "Milk"
End With
With tblItems
.Rows.Add(NewRow)
.AcceptChanges()
.Rows(tblItems.Rows.Count - 1).SetAdded()
End With
Dim Newtable As New DataTable
Newtable = tblItems.Clone
With Newtable
.ImportRow(tblItems.Rows(0))
.AcceptChanges()
.Rows(Newtable.Rows.Count - 1).SetAdded()
.AcceptChanges()
End With
الوظيفة Merge(DataTable): وتقوم بدمج الجدول المعطى مع الجدول الحالي. سأشرحها لاحقاً في استعراض العمليات على الجداول.
PHP كود :
Dim tblItems As New DataTable("Items")
Dim column As New DataColumn("id", GetType(System.Int32))
column.AutoIncrement = True
tblItems.Columns.Add(column)
column = New DataColumn("item", GetType(System.String))
tblItems.Columns.Add(column)
tblItems.PrimaryKey = New DataColumn() {tblItems.Columns(0)}
Dim NewRow As DataRow
NewRow = tblItems.NewRow
With NewRow
.Item("id") = 1
.Item("item") = "Milk"
End With
tblItems.Rows.Add(NewRow)
Dim Newtable As New DataTable
Newtable.Merge(tblItems)
MsgBox(Newtable.Rows(0).Item("id"))
الوظيفة Merge(DataTable, Boolean): وتقوم بدمج الجدول المعطى مع الجدول الحالي مع إعطاء الإمكانية لحفظ التغييرات من عدمه.
PHP كود :
' Create a new DataTable.
Dim tblItems As New DataTable("Items")
' Add two columns to the table:
Dim column As New DataColumn("id", GetType(System.Int32))
column.AutoIncrement = True
tblItems.Columns.Add(column)
column = New DataColumn("item", GetType(System.String))
tblItems.Columns.Add(column)
' Set primary key column.
tblItems.PrimaryKey = New DataColumn() {tblItems.Columns(0)}
Dim Newtable As New DataTable("MoreFields")
column = New DataColumn("Quantity", GetType(System.Int32))
Newtable.Columns.Add(column)
column = New DataColumn("Description", GetType(System.String))
Newtable.Columns.Add(column)
tblItems.Merge(Newtable, True)
MsgBox(tblItems.Columns(2).ColumnName)
الوظيفة NewRow: وتقوم بإنشاء DataRow بنفس تركيبة الجدول. بحيث تراعى أنواع البيانات وأحجامها وإعداداتها لكل عمود.
PHP كود :
Dim TheNewRow As DataRow
TheNewRow = tblItems.NewRow
With TheNewRow
.Item("id") = 1
.Item("item") = "Milk"
End With
الوظيفة Reset: وتقوم بإعادة ضبط الجدول إلى حالته القديمة. وحذف كافة البيانات المخزنة فيه، بالإضافة إلى الفهارس والعلاقات والأعمدة.
PHP كود :
tblItems.Reset()
الوظيفة Select: وتقوم باسترجاع مصفوفة تمثل كافة الـDataRows بالجدول.
PHP كود :
Dim CompanyDataSet As New DataSet("Company")
Dim TheSupplierTable As DataTable = CompanyDataSet.Tables("Suppliers")
Dim SelectedRows() As DataRow = TheSupplierTable.Select()
ويمكن الوصول إلى كل صف في هذه المصفوفة من خلال الـIndex:
PHP كود :
MsgBox(SelectedRows(0).Item("SupplierName"))
الوظيفة Select(String): وتقوم باسترجاع مصفوفة تمثل الـDataRows التي تخضع للمعايير المحددة.
PHP كود :
Dim CompanyDataSet As New DataSet("Company")
Dim TheSupplierTable As DataTable = CompanyDataSet.Tables("Suppliers")
Dim expression As String
expression = "JoinData > #01-01-2013#"
Dim SelectedRows() As DataRow
SelectedRows = TheSupplierTable.Select(expression)
MsgBox(SelectedRows(0).Item("SupplierName"))
الوظيفة Select(String, String): وتقوم باسترجاع مصفوفة تمثل الـDataRows التي تخضع للمعايير المحددة بترتيب محدد.
PHP كود :
Dim CompanyDataSet As New DataSet("Company")
Dim TheSupplierTable As DataTable = CompanyDataSet.Tables("Suppliers")
Dim expression As String = "JoinDate > 01/01/2013"
Dim sortOrder As String = "SupplierName DESC"
Dim SelectedRows() As DataRow
SelectedRows = TheSupplierTable.Select(expression, sortOrder)
MsgBox(SelectedRows(0).Item("SupplierName"))
إضافة أعمدة (حقول) للجدول Adding Columns to DataTable
الحمد لله، وصلنا إلى الجزء المثير والممتع! إذ أنه بعد تعريف الكائن الذي يمثل DataTable، سيكون ذلك الكائن فارغاً، وبالتالي لا نستفيد منه شيئاً! والخطوة القادمة هي بالتأكيد إنشاء الحقول أو Data Columns.
يحتوي فضاء الأسماء System.Data أيضاً على كلاس يسمى DataColumn والذي يمثل حقلاً واحداً في تركيبة الجدول Table Schema.
ولإضافة حقل إلى الجدول، نقوم بتعريف كائن يمثل الجدول:
PHP كود :
Dim Customers As New DataTable("Customers")
ثم نعرف كائناً آخر يمثل الحقل، وأنبه هنا إلى أن الحد الأدنى لتعريف الحقل هو توفير اسم الحقل ونوع البيانات التي يحملها:
PHP كود :
Dim CustomerID As New DataColumn("ID", GetType(Long))
ففي السطر السابق، تم تعريف الكائن CustomerID على أنه كائن يمثل حقلاً اسمه ID ونوع بياناته Long.
بقيت خطوة أخيرة، وهي ضم الكائن الجديد للجدول:
PHP كود :
Customers.Columns.Add(CustomerID)
وفي السطر السابق، تم استخدام الوظيفة Add التابعة لتجمع الحقول Columns لإضافة الحقل الجديد إلى الجدول. ونفعل ذلك لكل عمود جديد. أو بطريقة أخرى، وهي باستخدام الوظيفة Add التابعة لتجمع الحقول Columns لإضافة حقول جديدة دون تعريف كائنات تمثل كل الحقول:
PHP كود :
Dim Customers As New DataTable("Customers")
Customers.Columns.Add("ID", GetType(Long))
Customers.Columns.Add("CustomerName", GetType(String))
Customers.Columns.Add("BirthDay", GetType(Date))
خصائص الكلاس DataColumn
الكود السابق يوضح طريقة إنشاء الحقول بأبسط الطرق، وبالحد الأدنى من المعلومات المتعلقة بالحقول. ولكن هناك الكثير من الخصائص الأخرى التي تجعل من إنشاء الحقول وضمها للجدول أكثر احترافية وإتقاناً، أذكر منها على سبيل المثال:
الخاصية AllowDBNull: وتحمل قيمة منطقية Boolean، وتحدد ما إذا كان من المسموح أن لا يحمل هذا الحقل أية قيمة، أي قيمته = Null.
PHP كود :
Dim column As DataColumn
column = New DataColumn("ID", System.Type.GetType("System.Int32"))
column.AllowDBNull = True
أو
PHP كود :
Dim column As DataColumn
column = New DataColumn("ID", System.Type.GetType("System.Int32"))
column.AllowDBNull = False
ويمكن استعمال الكلاس System.DBNull لاختبار القيمة قبل تخزينها لاحقاً في هذا الحقل (تلقائياً: كل الحقول تسمح بالقيمة Null):
PHP كود :
If (DBNull.Value.Equals(FieldValue)) Then
Do something
End If
وكذلك توجد دالة في فجول بيسك وظيفتها فحص قيم المتغيرات:
PHP كود :
If (IsDBNull(FieldValue)) Then
Do something
End If
الخصائص AutoIncrement، وAutoIncrementSeed وAutoIncrementStep: تدير هذه الخصائص عملية الزيادة التلقائية لقيم الحقول التي تحمل هذه الميزة، فعند تطبيقها، يتم زيادة القيم تلقائياً عند إضافة سجلات جديدة بمقادير تتحدد من خلال الخاصيتين AutoIncrementSeed وAutoIncrementStep. وبشكل تلقائي فإن الخاصية AutoIncrement مضبوطة على الوضع False، وبالتالي فإن هذه الآلية لا تعمل.
PHP كود :
Dim column As DataColumn = New DataColumn
column.DataType = System.Type.GetType("System.Int32")
With column
.AutoIncrement = True
.AutoIncrementSeed = 1000
.AutoIncrementStep = 10
End With
الخاصية ColumnName: وهي خاصية نصية تمثل اسم الحقل. ويتم تحديدها وضبطها وقت إنشاء الحقل.
PHP كود :
Dim column As New DataColumn
With column
.ColumnName = "CustomerName"
.AllowDBNull = True
End With
MsgBox(column.ColumnName)
الخاصية DataType: وتمثل نوع البيانات التي سيحملها الحقل. ويتم تحديدها وضبطها وقت إنشاء الحقل، وإذا ما تم إضافة البيانات، لا يمكن تعديل نوعها.
PHP كود :
Dim column As New DataColumn
With column
.ColumnName = "FirstName"
.DataType = System.Type.GetType("System.String")
End With
MsgBox(column.DataType.ToString)
الخاصية DefaultValue: وتمثل القيمة الافتراضية للحقل، ويمكن لأي حقل أن يحمل قيمة افتراضية، ويتم تخزين هذه القيمة كلما تم إنشاء سجل جديد، ويمكن تعديلها لاحقاً دون أية مشكلة.
PHP كود :
Dim column As New DataColumn
With column
.ColumnName = "FirstName"
.DataType = System.Type.GetType("System.String")
.DefaultValue = "None"
End With
MsgBox(column.DefaultValue)
الخاصية MaxLength: وهي خاصة بالحقول التي تحمل قيماً نصية، وتحدد طول النص الذي سيحمله هذا الحقل، وتلقائياً: قيمته هي -1، بمعنى أنه لا حد لطول النص.
PHP كود :
Dim column As New DataColumn
With column
.ColumnName = "FirstName"
.DataType = System.Type.GetType("System.String")
.MaxLength = 20
.DefaultValue = "None"
End With
الخاصية ReadOnly: حقول القراءة فقط لا يمكن تعديل قيمها في أي سجل قد تمت إضافته فعلاً للجدول، وتلقائياً: جميع قيم الحقول قابلة للتعديل.
PHP كود :
Dim column As New DataColumn
With column
.ColumnName = "FirstName"
.DataType = System.Type.GetType("System.String")
.ReadOnly = True
.DefaultValue = "None"
End With
الخاصية Unique: وهي خاصية منطقية، إذا ضبطت بالقيمة True، فإن الحقل لا يسمح بحمل قيمتين متساويتين، وكذلك في هذا النوع من الحقول لا يمكن تخزين قيمة Null.
PHP كود :
Dim column As New DataColumn
With column
.ColumnName = "ID"
.DataType = System.Type.GetType("System.Int32")
.Unique = True
End With
PHP كود :
Dim Customers As New DataTable("Customers")
Customers.Columns.Add("ID", GetType(Long))
Customers.Columns.Add("CustomerName", GetType(String))
Customers.Columns.Add("BirthDay", GetType(Date))
Customers.PrimaryKey = {Customer.Columns("ID")}
عند إضافة DataColumn للجدول DataTable، يتم إضافته إلى ما يعرف بـColumns Collection أو تجمع الأعمدة (الحقول). هذه الحقول لا تحمل أية قيم إلى حد الآن، وإنما يتم إضافة البيانات عن طريق ما يعرف بـRows Collection أو تجمع الصفوف والذي يتبع الكائن DataTable كما سنرى لاحقاً إن شاء الله.
إنشاء صفوف جديدة Creating New Rows
إن عملية إنشاء الجداول Creating DataTables وأعمدتها DataColumns هي عملية أساسية قبل المضي قدماً للخطوة اللاحقة وهي: عملية إضافة البيانات للجدول أو "إنشاء سجلات (صفوف Rows) جديدة".
وكما تعلمنا سابقاً، فإننا إذ ننشئ الأعمدة (الحقول DataColumns) إنما ننشئ قوالب لا نهائية من حيث العدد، يمكننا حفظ البيانات فيها بالصورة التي نريد. والآن، أود أن أحدثكم عن الكلاس DataRow..
الكلاس DataRow
ويمثل صفاً كاملاً من الـDataColumns التي يتكون منها الـDataTables. آخذاً في الاعتبار نوع وحجم كل عمود DataColumn في الجدول.
أهم خصائص الكلاس DataRow
الخاصية Item(DataColumn): ومن خلالها يتم ضبط / استرجاع القيمة المخزنة بحقل محدد.
PHP كود :
Dim Customers As New DataTable("Customers")
Customers.Columns.Add("ID", GetType(Long))
Customers.Columns.Add("CustomerName", GetType(String))
Customers.Columns.Add("RegistrationDate", GetType(Date))
Customers.PrimaryKey = {Customers.Columns("ID")}
Dim NewRow As DataRow
NewRow = Customers.NewRow
With NewRow
.Item("ID") = 1
.Item("CustomerName") = "Abubaker Swedan"
.Item("RegistrationDate") = Now.Date
End With
Customers.Rows.Add(NewRow)
MsgBox(Customers.Rows(0).Item("CustomerName"))
MsgBox(Customers.Rows(0).Item("RegistrationDate"))
PHP كود :
Dim Customers As New DataTable("Customers")
Customers.Columns.Add("ID", GetType(Long))
Customers.Columns.Add("CustomerName", GetType(String))
Customers.Columns.Add("RegistrationDate", GetType(Date))
Customers.PrimaryKey = {Customers.Columns("ID")}
Dim NewRow As DataRow
NewRow = Customers.NewRow
With NewRow
.Item(0) = 1
.Item(1) = "Abubaker Swedan"
.Item(2) = Now.Date
End With
Customers.Rows.Add(NewRow)
MsgBox(Customers.Rows(0).Item(1))
MsgBox(Customers.Rows(0).Item(2))
PHP كود :
Dim Customers As New DataTable("Customers")
Customers.Columns.Add("ID", GetType(Long))
Customers.Columns.Add("CustomerName", GetType(String))
Customers.Columns.Add("RegistrationDate", GetType(Date))
Customers.PrimaryKey = {Customers.Columns("ID")}
Dim NewRow As DataRow
NewRow = Customers.NewRow
With NewRow
.Item("ID") = 1
.Item("CustomerName") = "Abubaker Swedan"
.Item("RegistrationDate") = Now.Date
End With
Customers.Rows.Add(NewRow)
MsgBox(Customers.Rows(0).Item("CustomerName"))
MsgBox(Customers.Rows(0).Item("RegistrationDate"))
الخاصية Table: ومن خلالها يتم استرجاع اسم الجدول DataTable الذي ينتمي إليه الصف.
PHP كود :
Dim Customers As New DataTable("Customers")
Customers.Columns.Add("ID", GetType(Long))
Customers.Columns.Add("CustomerName", GetType(String))
Customers.Columns.Add("RegistrationDate", GetType(Date))
Customers.PrimaryKey = {Customers.Columns("ID")}
Dim NewRow As DataRow
NewRow = Customers.NewRow
With NewRow
.Item("ID") = 1
.Item("CustomerName") = "Abubaker Swedan"
.Item("RegistrationDate") = Now.Date
End With
Customers.Rows.Add(NewRow)
MsgBox(NewRow.Table.TableName)
الوظيفة Delete: وتقوم بحذف الـDataRow.
PHP كود :
Dim tblItems As New DataTable("Items")
Dim column As New DataColumn("id", GetType(System.Int32))
column.AutoIncrement = True
tblItems.Columns.Add(column)
column = New DataColumn("item", GetType(System.String))
tblItems.Columns.Add(column)
tblItems.PrimaryKey = New DataColumn() {tblItems.Columns(0)}
Dim NewRow As DataRow
NewRow = tblItems.NewRow
With NewRow
.Item("id") = 1
.Item("item") = "Milk"
End With
With tblItems
.Rows.Add(NewRow)
.AcceptChanges()
.Rows(tblItems.Rows.Count - 1).SetAdded()
End With
NewRow = tblItems.NewRow
With NewRow
.Item("id") = 2
.Item("item") = "Cheese"
End With
With tblItems
.Rows.Add(NewRow)
.AcceptChanges()
.Rows(tblItems.Rows.Count - 1).SetAdded()
End With
MsgBox(tblItems.Rows.Count)
tblItems.Rows(0).Delete()
tblItems.AcceptChanges()
MsgBox(tblItems.Rows.Count)
وكما تلاحظون في الكود، فإنني استعملت الوظيفة AcceptChanges لتأكيد الحذف. وسنتطرق لها في معالجة الحزم لاحقاً إن شاء الله.
الوظيفة IsNull(DataColumn): وتحدد ما إذا كانت القيمة التي يحملها الـDataColumn هي Null.
PHP كود :
If NewRow.IsNull(ColumnObject) Then
MsgBox("Empty Column")
Else
MsgBox("it is not null value")
End If
الوظيفة IsNull(Int32): وتحدد ما إذا كانت القيمة التي يحملها الـDataColumn (بدلالة فهرسه) هي Null.
PHP كود :
If NewRow.IsNull(1) Then
MsgBox("Empty Column")
Else
MsgBox("it is not null value")
End If
الوظيفة IsNull(String): وتحدد ما إذا كانت القيمة التي يحملها الـDataColumn (بدلالة اسمه) هي Null.
If NewRow.IsNull("CustomerName") Then
MsgBox("Empty Column")
Else
MsgBox("it is not null value")
End If
يدعم الكلاس DataTable الطريقة NewRow لتوليد صف جديد يخضع لإعدادات الـDataColumns، من حيث نوع الحقل وطوله وخصائصه الأخرى وذلك لكل حقل من الحقول التي يحتوي عليها DataTable.
ولفتح صف (سجل DataRow) جديد في الجدول:
PHP كود :
Dim TheNewRow As DataRow = TableName.NewRow()
بعد تنفيذ السطر البرمجي السابق، يتم وبشكل تلقائي إنشاء صف بيانات جديد بحيث يراعى فيه خصائص كل حقل، ويتم وضع القيمة Null في كافة الحقول، عدا تلك التي لها قيم افتراضية Default Values، أو التي خاصية AutoIncrement لها = True.
هناك المزيد من هذه الوظائف، سأتطرق لها لاحقاً مثل الوظيفة SetAdded وSetModified.
ضبط قيم الحقول في الـDataRow الجديد
يتضمن الكلاس DataRow خاصية مهمة وهي Item، والتي تعطي إمكانية الوصول إلى كل DataColumn معرّف في الـDataTable اعتماداً على اسم الحقل أو رقم ترتيبه (ابتداء من الصفر) أو متغير يمثل الـDataColumn، و السنّة المتبعة هي الاعتماد على اسم الحقل تجنباً لأخطاء غير مقصودة، وتوضيحاً للكود، مع الأخذ في الاعتبار خصائص كل حقل على حدة.
PHP كود :
Dim TheNewRow As DataRow = TableName.NewRow()
TheNewRow.Item("ID")= 100
TheNewRow.Item(0)= 100
Dim SpecificRow As DataColumn = TableName.Columns(0)
TheNewRow.Item(SpecificRow)= 100
في الكود السابق تم ضبط قيمة أول حقل في الجدول (ID) من خلال اسم الحقل مرة، ورقم ترتيبه مرة ، ومن خلال مرجع يمثل الحقل المطلوب مرة ثالثة.
الخاصية Item هي الخاصية التلقائية للكلاس DataRow، ولذلك يمكن الاستغناء عن ذكرها وكتابة:
PHP كود :
Dim TheNewRow As DataRow = TableName.NewRow()
TheNewRow("ID")= 100
كما يمكن استعمال علامة التعجب (!) لتشير إلى اسم الحقل (لا تدعم رقم فهرس الحقل) في الجدول:
PHP كود :
Dim Customers As New DataTable("Customers")
Customers.Columns.Add("ID", GetType(Long))
Customers.Columns.Add("CustomerName", GetType(String))
Customers.Columns.Add("RegistrationDate", GetType(Date))
Customers.PrimaryKey = {Customers.Columns("ID")}
Dim NewRow As DataRow
NewRow = Customers.NewRow
NewRow!ID = 1
NewRow!CustomerName = "Abubaker Swedan"
NewRow!RegistrationDate = Now.Date
Customers.Rows.Add(NewRow)
حفظ البيانات في الجدول DataTable
بعد ضبط وتعيين القيم في السجل الجديد، تكون الخطوة اللاحقة هي ضم هذا السجل إلى الجدول DataTable، مستعملين الطريقة .Rows.Add التابعة للـDataTable:
PHP كود :
Dim TheNewRow As DataRow = TableName.NewRow()
TheNewRow.Item("ID")= 100
TableName.Rows.Add(TheNewRow)
كما يمكن استعمال طريقة أخرى، وهي بتنفيذ الطريقة Rows.Add وإرسال قيم الحقول كبارامترات:
PHP كود :
Dim TheNewRow As DataRow = TableName.NewRow()
TableName.Rows.Add(100, “Abubaker”, “Tripoli”, …)
وأي طريقة اخترنا، فإن الوظيفة Add تختبر القيم المرسلة من حيث توافقها مع تركيبة الجدول وحقوله، وترفض القيم التي لا تتماشى مع القواعد.
الوصول إلى الصف المطلوب في جدول DataTable
أو بصيغة أخرى، طريقة تحديد صف معين أو مجموعة من الصفوف في جدول لإجراء عمليات عليها. وتوجد عدة طرق لاسترجاع الصفوف المطلوبة منها:
أ) استرجاع الصفوف بدلالة قيم الأعمدة
وذلك باستخدام الوظيفة Select Method، التابعة للـDataTable
PHP كود :
Dim foundRows() As Data.DataRow
foundRows = DataSet1.Tables("Customers").Select("LastName = 'Swedan'")
ففي هذا الكود تم تعريف مصفوفة لتجمع بداخلها الصفوف المسترجعة من عملية البحث باستخدام الطريقة Select، والتي مررنا لها قيمة الحقل LastName. فإن تم العثور على السجلات المطلوبة فإنها تخزن في تلك المصفوفة.
ويمكن معرفة عدد الصفوف المسترجعة من خلال الكود التالي:
PHP كود :
Dim RowsCount As Integer
RowsCount = foundRows.Count
ويمكن الوصول إلى حقول كل صف بالكيفية التالية:
PHP كود :
Dim FirstColValue As Integer
FirstColValue = foundRows(0).Item("OrderID")
ب) استرجاع الصفوف بدلالة قيمة الحقل المفتاحي Primary Key Value
وفي هذه الحالة نستخدم الطريقة Find التابعة للتجمع DataRowCollection ونرسل لها القيمة المفتاحية كبارامتر:
PHP كود :
Dim s As String = "primaryKeyValue"
Dim foundRow As DataRow = dataset1.Tables("Customers").Rows.Find(s)
If foundRow IsNot Nothing Then
MsgBox(foundRow(1).ToString())
Else
MsgBox("A row with the primary key of " & s & " could not be found")
End If
تعديل البيانات في الجدول DataTable
لتعديل بيانات أي صف في جدول DataTable، يلزمنا كبداية تحديد الصف المطلوب تعديل بياناته، ومن ثم إسناد القيم المناسبة لكل حقل من حقوله.
ولمعرفة الصف المطلوب تعديله، نستخدم الطريقة Select Method التابعة للـDataTable بالصورة التالية:
PHP كود :
Dim customerRow() As Data.DataRow
customerRow = DataSet1.Tables("Customers").Select("CustomerID = 107")
customerRow(0)("CompanyName") = "New Company Name"
customerRow(0)("City") = "Tripoli"
ففي الكود السابق، الحقل CustomerID هو الحقل المفتاحي للجدول Primary Key، وبالتالي عند استخدام الطريقة Select وتمرير رقم الزبون فإن النتيجة هي إرجاع مصفوفة customerRow() تحتوي على صف واحد فقط، إذ أن رقم الزبون لا يتكرر. ثم استعملنا الرقم (0) للتعبير عن أول صف مسترجع في المصفوفة، وعدلنا قيم الحقول المقصودة.
بالإمكان تعديل الكود السابق والخاص بضبط القيم إلى:
PHP كود :
customerRow(0).Item("CompanyName") = "New Company Name"
customerRow(0).Item("City") = "Tripoli"
ولكن كما قلتُ سابقاً أن الخاصية Item هي الخاصية التلقائية للكلاس DataRow، ولذلك يمكن الاستغناء عن ذكرها.
وفي حالة أننا نعلم رقم ترتيب الصف المطلوب تعديله، بدلالة رقم الجدول في الـDataSet نكتب:
PHP كود :
DataSet1.Tables(0).Rows(4).Item(1) = "New Company Name"
DataSet1.Tables(0).Rows(4).Item(2) = "Tripoli"
أو بدلالة اسم الجدول:
PHP كود :
DataSet1.Tables("Customers").Rows(4).Item(1) = "New Company Name"
DataSet1.Tables("Customers").Rows(4).Item(2) = "Tripoli"
عرض بيانات الجدول Viewing Data in a DataTable
يمكننا الوصول لبيانات الجدول من خلال استعمال التجمعات Rows وColumns الخاصة بالـDataTable. وكذلك استعمال الطريقة Select Method لاسترجاع مجموعة من السجلات التي تخضع لشروط معينة وترتيب معين وحالة صف معينة.
بالإضافة إلى استعمال الطريقة Find Method التابعة للتجمع DataRowCollection للبحث عن سجل معين عن طريق مفتاحه الأساسي.
استعمال الطريقة Select Method يرجع مجموعة من كائنات الـDataRow ، تنطبق عليها شروطنا، وتقبل بارامترات تمثل:
• صيغة الفرز (الشروط) Filter expression.
• طريقة الترتيب Sort expression.
• حالة كل صف DataViewRowState.
صيغة الفرز تحدد الصفوف المسترجعة بناء على قيم الحقول DataColumn مثلاً LastName = “Swedan”.
وطريقة الترتيب تحدد من خلال جملة Sql مثلاً ORDER BY LastName DESC.
أما حالة كل صف فسنتعرف عليها لاحقاً إن شاء الله في موضوع: حالة الصف Row State.
حذف البيانات من جدول Removing Data from DataTable
يمكن حذف الصفوف من الجدول DataTable باستخدام:
• الطريقة Remove التابعة للتجمع DataTable.Rows.
• الطريقة RemoveAt التابعة للتجمع DataTable.Rows.
والطريقة Remove Method تأخذ متغيراً يمثل صفاً في الجدول:
PHP كود :
Dim SelectedRow As DataRow = SelectedTable.Rows(0)
SelectedTable.Rows.Remove(SelectedRow)
أما الطريقة RemoveAt Method فتأخذ رقم فهرس الصف مباشرة:
PHP كود :
SelectedTable.Rows.RemoveAt(0)
وكل الطرق تؤدي إلى مكة.
ويمكن حذف جميع الصفوف بأمر واحد، وذلك باستخدام الطريقة Clear Method التابعة للكائن DataTable.Rows:
PHP كود :
SelectedTable.Rows.Clear()
ويجب ملاحظة أنه عند حذف الصفوف بهذه الطريقة، فإنه لا يمكننا التراجع عن عملية الحذف إطلاقاً، وهذا ما سنفهمه من الموضوع التالي.
معالجة الحزم / الدفعات Batch Processing
جميع العمليات التي قمنا بها سابقاً هي عمليات مباشرة تتم على سجلات الجدول وحقوله، الأمر للوهلة الأولى جيد ورائع، ولكن لهذا النظام عيوب منها عدم القدرة على استرجاع قيم سابقة للحقول، ولا يمكن التراجع عن أي عملية والرجوع إلى الحالة السابقة.
ADO.NET يوفر مزايا جديدة بحيث يمكننا عمل تغييرات على عدة سجلات، وبعدها نقرر هل نطبق هذه التغييرات أم نتجاهلها! وهذه الطريقة تسمى: معالجة الحزم أو الدفعات.
وللاستفادة من هذه الطريقة في المعالجة، ببساطة نقوم بإحداث التغييرات التي نريد، وعندما نكون جاهزين لتطبيق هذه التغيرات:
• نستخدم الطريقة AcceptChanges Method التابعة للـDataTable ليتم تطبيق التغييرات وتحديث بيانات الجدول.
• أو نستخدم الطريقة RejectChanges Method لرفض التغييرات غير المحفوظة والحفاظ على بيانات الجدول كما هي دون تغيير.
يمكن تطبيق هاتين الطريقتين حتى على الـDataRows. فكل DataRow يدعم هاتين الطريقتين، ولكن استخدام AcceptChanges أو RejectChanges على الجدول بأكمله أفضل من استعمالهما مع كل صف على حدة، لأنه سيتم الدوران على كافة الصفوف التي حدث بها التغيير وتطبيقها (في حال استعمال AcceptChanges) أو رفض التغييرات (في حال استعمال RejectChanges).
PHP كود :
SelectedTable.AcceptChanges()
SelectedTable.RejectChanges()
حالة الصف Row State
في أثناء إجراء التغييرات على الصف، يقوم ADO.NET بحفظ النسخة الأصلية والنسخة المعدلة لكافة الحقول التي يحتويها هذا الصف، وكذلك بمراقبة وتحديد الصفوف المضافة و/أو المحذوفة من الجدول، بحيث يمكن أن نعود للنسخة الأصلية حين الحاجة. يفعل ADO.NET كل ذلك من خلال حفظ حالة كل حقل لكل الصفوف ويتم تحديث قيمة الخاصية DataRow.RowState لكل صف على حدة، والتي تحتمل إحدى القيم التالية:
• DataRowState.Detached: وهي الحالة الافتراضية لأي صف لم يتم إضافته بعد إلى DataTable.
• DataRowState.Added: وهي حالة كل صف تم إضافته إلى DataTable ولكن لم تأكيد الإضافة. بحيث لو استعملنا RejectChanges يتم حذفها فوراً.
• DataRowState.UnChanged: وهي الحالة الافتراضية لأي صف موجود مسبقاً بالجدول ولم تتم عليه أي عملية تعديل منذ آخر مرة تم فيها استدعاء الطريقة AcceptChanges Method. وهي الحالة الافتراضية أيضاً لكافة السجلات التي تم إنشاؤها من خلال الطريقة NewRow.
• DataRowState.Deleted: الصفوف المحذوفة لا يتم إزالتها فعلياً من الجدول إلى أن يتم استدعاء الطريقة AcceptChanges، بل يتم تأشيرها على أنها ستحذف من خلال هذه الخاصية.
• DataRowState.Modified: أي صف تم تعديل حقوله بأي طريقة يؤشر على أنه Modified.
ففي كل مرة نقوم بإضافة أو تعديل صف، يتم تحديث حالته فوراً، على عكس عملية الحذف من خلال Rows.Remove و Rows.RemoveAt، فإنه يحدث التفاف حول نظام تتبع حالات السجلات هذا، ولا يتم تحديث الحالة على نفس المنوال، لأنه يتم حذف الصفوف مباشرة، ولا يجعلها تخضع لنظام معالجة الحزم.
ولحل هذه المشكلة، نستعمل الطريقة Delete Method التابعة للـDataRow عوضاً عن Rows.Remove و/أو Rows.RemoveAt، فهي لا تقوم بحذف الصفوف، بل بتغيير حالتها إلى Deleted، وبالتالي نستطيع تأكيد الحذف من خلال الطريقة AcceptChanges، أو التراجع عن الحذف من خلال RejectChanges.
PHP كود :
TheRow.Delete()
عند استدعاء الطريقة AcceptChanges سواء من خلال DataSet أو DataTable أو DataRow فإن يتم حذف كافة السجلات التي حالتها = Deleted، وتطبيق التعديلات التي حصلت على السجلات الأخرى بحيث تحل القيم الجديدة Current Values محل القيم الأصلية Original Values.
أما عند استدعاء الطريقة RejectChanges، فإنه يتم حذف كافة السجلات التي حالتها = Added، وتعطى باقي السجلات الحالة Unchanged، وتلغى التعديلات التي حصلت على السجلات الأخرى بحيث تحل القيم الأصلية Original Values محل القيم الجديدة Current Values.
وظائف أخرى للـDataRow
هناك بعض الوظائف الإضافية التي لم أذكرها عند حديثي عن الـDataRow ، مهمة تلك الوظائف هي ضبط حالة الصف مثل:
الوظيفة SetAdded: تقوم بتغيير الـDataState للـDataRow إلى Added.
PHP كود :
Dim tblItems As New DataTable("Items")
Dim column As New DataColumn("id", GetType(System.Int32))
column.AutoIncrement = True
tblItems.Columns.Add(column)
column = New DataColumn("item", GetType(System.String))
tblItems.Columns.Add(column)
tblItems.PrimaryKey = New DataColumn() {tblItems.Columns(0)}
Dim NewRow As DataRow
NewRow = tblItems.NewRow
With NewRow
.Item("id") = 1
.Item("item") = "Milk"
End With
With tblItems
.Rows.Add(NewRow)
.AcceptChanges()
.Rows(tblItems.Rows.Count - 1).SetAdded()
End With
الوظيفة SetModified: تقوم بتغيير الـDataState للـDataRow إلى Modified.
PHP كود :
Dim tblItems As New DataTable("Items")
Dim column As New DataColumn("id", GetType(System.Int32))
column.AutoIncrement = True
tblItems.Columns.Add(column)
column = New DataColumn("item", GetType(System.String))
tblItems.Columns.Add(column)
tblItems.PrimaryKey = New DataColumn() {tblItems.Columns(0)}
Dim NewRow As DataRow
NewRow = tblItems.NewRow
With NewRow
.Item("id") = 1
.Item("item") = "Milk"
End With
With tblItems
.Rows.Add(NewRow)
.AcceptChanges()
.Rows(tblItems.Rows.Count - 1).SetAdded()
End With
With tblItems
.Rows(0).Item("item") = "Cheese"
.AcceptChanges()
.Rows(0).SetModified()
End With
نُسخ الصف Row Versions
عند إجراء التعديلات والتغييرات سواء إضافة أو حذف أو تعديل في بيانات الصفوف، فإن ADO.NET يحتفظ بنسخ متعددة لكل صف حتى ولو تم تغيير قيمة حقل واحد فقط.
DataRowVersion
ويحتمل إحدى القيم التالية:
• DataRowVersion.Original: يعني الاحتفاظ بالقيم الأصلية للحقول منذ آخر استدعاء للطريقة AcceptChanges، ولا يشمل الصفوف الجديدة.
• DataRowVersion.Porposed: يعني أن قيمة حقل ما تغيرت، ولكن لم يتم تأكيد التغيير. هذه النسخة لا تتوفر حتى يتم البدء في عملية تعديل قيمة الحقل. بعد تأكيد التغييرات، تتحول القيمة إلى Original.
• DataRowVersion.Current: يعني أن التعديل جارٍ الآن، وعند تأكيده، تتحول القيمة إلى Original.
• DataRowVersion.Default: يعني النسخة التلقائية للصف. فالنسخة التلقائية للـ Added وModified وUnchanged هي Current، والنسخة التلقائية للـDeleted هي Original، والنسخة التلقائية للـDetached هي Proposed.
حيث Added وModified وUnchanged وDeleted و Detached هي حالات الصفوف.
فحص التغييرات الطارئة على محتويات جدول
قلتُ سابقاً أنه عند استعمال نظام معالجة الحزم، وفي حال حدث تغيير في الجدول، لا يتم تطبيق التعديلات إلا عند استدعاء الطريقة AcceptChanges Method. وبالتالي فالتغييرات تبقى معلقة pending حتى تطبيقها أو تجاهلها وإرجاع الجدول إلى سابق عهده (إلى حالته عند استدعاء AcceptChanges آخر مرة). وقلتُ أن عملية تتبع الصفوف تتم عن طريق:
• كل صف يحتوي على "RowState" وهي إحدى الحالات: Detached وAdded وModified وDeleted وUnchanged.
• كل صف تم تغيير محتوياته يتضمن نُسخاً مختلفة للصفوف: Original وProposed وCurrent وDefault.
معرفة ما إذا كان هناك تغيير في الصفوف
هناك طريقة Method تتبع الـDataSet هي: HasChanges، ذات قيمة منطقية، إذا ساوت True فإن هناك تغيير حدث على بعض الصفوف أو كلها. وفي تلك الحالة يمكن استدعاء الطريقة GetChanges التابعة للـDataSet و/أو للـDataTable لاسترجاع مصفوفة تحتوي على الصفوف المتغيرة، وهذه المصفوفة هي بمثابة DataSet أو DataTable مملوء بالصفوف المتغيرة فقط. ومن نافلة القول أنه يجب استدعاء الطريقة GetChanges قبل تطبيق التغييرات باستخدام الطريقة AcceptChanges، وإلا فلن نتحصل على أي صف!.
أ) استرجاع الصفوف المتغيرة من DataSet
وهنا نقوم بإنشاء DataSet وملئها بالصفوف المتغيرة:
PHP كود :
Dim changedRecords As DataSet = dataset1.GetChanges()
ب) استرجاع الصفوف المتغيرة من DataTable
وهنا نقوم بإنشاء DataTable وملئه بالصفوف المتغيرة:
PHP كود :
Dim changedRecordsTable As DataTable = Customers.GetChanges()
ج) استرجاع الصفوف المتغيرة بحسب نوعية التغيير (النسخة)
وهنا نرسل نوع الإصدارة إلى الطريقة GetChanges كبارامتر:
PHP كود :
Dim addedRecords As DataSet = dataset1.GetChanges(DataRowState.Added)
---------------