عرب تك
هل تريد التفاعل مع هذه المساهمة؟ كل ما عليك هو إنشاء حساب جديد ببضع خطوات أو تسجيل الدخول للمتابعة.

اذهب الى الأسفل
avatar
tarik
عدد المساهمات : 134
تاريخ التسجيل : 08/10/2012

الوضع المتصل والوضع المنفصل - ربط نموذج بقاعدة بيانات في الوضع المنفصل  Empty الوضع المتصل والوضع المنفصل - ربط نموذج بقاعدة بيانات في الوضع المنفصل

الخميس أكتوبر 10, 2013 6:12 pm

[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]

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

تعريفات :
لتحميل و تخزين البيانات, سنحتاج لحاوية الجداول DataSet و لكائن تبادل البيانات بين التطبيق و قاعدة البيانات OleDbDataAdapter. الكائنين المعرفين أسفله يتم تعريفهما على مستوى النموذج Form لإننا سنحتاج لخدماتهما طوال مدة تشغيل التطبيق :


الكود:

 ' كائن تحميل, تحرير, زيادة و حذف المعلومات
 Private MyAdapter As New OleDbDataAdapter
 ' الداتاست التي ستكون الحاوية للجداول التي سيملأها الكائن مايأدابتر
 Private MyDataSet As DataSet


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


الكود:

' جملة الربط
 Dim ConString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source =.\AccessDB.mdb"
 ' إنشاء الكائن و تهيئته بكائن الربط و جملة الإستعلام
 MyAdapter = New OleDbDataAdapter("SELECT * FROM UserInfo", ConString)
 ' تهيئة كائن جملة تحرير التسجيلات مع البرامترز
 MyAdapter.UpdateCommand = New OleDbCommand("UPDATE UserInfo SET [Login] = @Login, [Password] = @Password, GroupID = @GroupID WHERE ID = @ID", MyAdapter.SelectCommand.Connection)
 MyAdapter.UpdateCommand.Parameters.Add("@Login", OleDbType.WChar, 32, "Login")
 MyAdapter.UpdateCommand.Parameters.Add("@Password", OleDbType.WChar, 32, "Password")
 MyAdapter.UpdateCommand.Parameters.Add("@GroupID", OleDbType.BigInt, 1, "GroupID")
 MyAdapter.UpdateCommand.Parameters.Add("@ID", OleDbType.BigInt, 1, "ID")
 ' تهيئة كائن أمر الحدف مع البرمتر مرجع التسجيل المراد حذفه
 MyAdapter.DeleteCommand = New OleDbCommand("DELETE FROM UserInfo WHERE ID = @ID", MyAdapter.SelectCommand.Connection)
 MyAdapter.DeleteCommand.Parameters.Add("@ID", OleDbType.BigInt, 1, "ID")
 ' تهيئة كائن أمر زيادة التسجيلات من الداتاست إلى الجدول على قاعدة البيانات
 MyAdapter.InsertCommand = New OleDbCommand("INSERT INTO UserInfo ([Login], [Password], GroupID) VALUES(@Login, @Password, @GroupID)", MyAdapter.SelectCommand.Connection)
 MyAdapter.InsertCommand.Parameters.Add("@Login", OleDbType.WChar, 32, "Login")
 MyAdapter.InsertCommand.Parameters.Add("@Password", OleDbType.WChar, 32, "Password")
 MyAdapter.InsertCommand.Parameters.Add("@GroupID", OleDbType.BigInt, 1, "GroupID")
 ' إنشاء و تهيئة الداتاست
 MyDataSet = New DataSet("AccessDB")
 ' تحميل تسجيلات الجدول من قاعدة البيانات إلى الداتاست
 MyAdapter.Fill(MyDataSet, "UserInfo")

 ' تحميل بيانات أسماء المجموعات
 Dim adptr As New OleDbDataAdapter("SELECT * FROM GroupInfo", MyAdapter.SelectCommand.Connection)
 adptr.Fill(MyDataSet, "GroupInfo")
 adptr.Dispose()



بعد ذلك, سنقوم بربط مربع ComboBox الذي سيقوم بمهمة إضهار المجموعة التي ينتمي إليها المستخدم المضهر في التسجيل الحالي و يمكن المستخدم كذلك من إمكانية اختيار مجموعة بين المجموعات الموجودة على الجدول GroupInfo. الخاصية DataSource نحدد فيها الجدول من فئة DataTable الموجود فيها أسماء المجموعات. الخاصية DisplayMember نحدد فيها اسم الحقل الذي يحوي اسم المجموعة. الخاصية ValueMember نحددها على اسم الحقل الذي يحوي مرجع التسجيل التلقائي الترقيم لاسم المجموعة الذي يربطها بالجدول UserInfo و الحقل GroupID :


الكود:

 ' ربط كومبوبوكس مجموعات المستخدمين مع الجدول الموجود على الذاكرة الحية
 GroupComboBox.DataSource = MyDataSet.Tables("GroupInfo")
 GroupComboBox.DisplayMember = "Name"
 GroupComboBox.ValueMember = "ID"



بعد ذلك, سنقوم بربط كل مربع من مربعات النموذج بالحقل المناسب من حقول الجدول UserInfo, نستعمل الخاصية DataBindings لمربعات التحكم للمنادة على دالتها Add التي نحدد من خلالها خاصية المربع التي نريد ربطها مع حقل لجدول ما على الحاوية DataSet. مربعات النص نربط الخاصية Text لكل منها مع الحقل المناسب حتى تظهر معلومات التسجيل الحالي أوتوماتيكيا و يتم تحديث محتوى حقل التسجيل عندما يقوم المستخدم بتحديث محتوى مربع النص. بالنسبة لمربع الكومبوبوكس فسنقوم بربط الخاصية SelectedValue التي تمثل معرف تسجيل الجدول GroupInfo الذي يمثل اسم المجموعة التي ينتمي إليها المستخدم. المعامل الأخير للدالة Add نحدد من خلاله أن عملية تحديث محتوى مربع التحكم يتم وقت حدوث الحدث Validated.


الكود:

 ' ربط مربعات النموذج مع الحقول الموجودة على الذاكرة الحية
 IDTextBox.DataBindings.Add("Text", MyDataSet, "UserInfo.ID", True, DataSourceUpdateMode.OnValidation)
 NameTextBox.DataBindings.Add("Text", MyDataSet, "UserInfo.Login", True, DataSourceUpdateMode.OnValidation)
 PasswordTextBox.DataBindings.Add("Text", MyDataSet, "UserInfo.Password", True, DataSourceUpdateMode.OnValidation)
 GroupComboBox.DataBindings.Add("SelectedValue", MyDataSet, "UserInfo.GroupID", True, DataSourceUpdateMode.OnValidation)


بعد ذلك, سنقوم بتسجيل دالة للحدث Positionchanged للكائن BindingManagerBase الذي سيقوم بالمناداة على الدالة UserInfo_Positionchanged في كل مرة يقوم فيها المستخدم بالانتقال من تسجيل إلى تسجيل آخر حتى نتمكن من إضهار بعض المعلومات عن التسجيل الحالي للمستخدم :


الكود:

' تحديد دالة الحدث تغيير التسجيل الحالي لإضهار معلومات
 ' حول التسجيل الحالي للمستخدم
 AddHandler Me.BindingContext(MyDataSet, "UserInfo").PositionChanged, AddressOf UserInfo_PositionChanged


الفئة BindingManagerBase تقوم بعمليات التحديث المتزامن بين الحقول و مربعات التحكم المرتبطة بينها على نفس النموذج Form. للحصول على الكائن من فئة BindingManagerBase لجدول ما :

الكود:

Dim mngr as BindingManagerBase = BindingContext(MyDataSet, "TableName")



الكائن الذي نحصل عليه يمكننا من الوصول إلى التسجيلات DataRow عن طريق الخاصية Current و يمكننا من تحديد و إضهار أي تسجيل عن طريق تحديد رقم التسجيل في الخاصية Position كما يمكننا من معرفة عدد التسجيلات في الجدول المرتبط عن طريق الخاصية Count...

بعد ذلك, سنقوم بتهيئة الحقل ID للجدول UserInfo الموجود على الذاكرة الحية على الحاوية MyDataSet ليصبح كمثيله على قاعدة البيانات تلقائي الترقيم بتحديد الخاصية AutoIncrement على true. لتحديد العدد الذي يبدأ منه الترقيم التلقائي, نقوم بتحديده في الخاصية AutoIncrementSeed. لتحديد خطوة الترقيم التلقائي عند زيادة تسجيل جديد, نقوم بتحديد العدد المناسب في الخاصية AutoIncrementStep.


الكود:

 ' تهيئة الترقيم التلقائي للتسجيلات الموجودة على الداكرة الحية
 MyDataSet.Tables("UserInfo").Columns("ID").AutoIncrement = True
 MyDataSet.Tables("UserInfo").Columns("ID").AutoIncrementStep = 1
 MyDataSet.Tables("UserInfo").Columns("ID").AutoIncrementSeed = 1


للوصول إلى الكائن الممثل لحقل ما DataColumn لجدول ما DataTable :


الكود:

MyDataSet.Tables("TableName").Columns("FieldName")



بعد التهيئة الأولية للحقل التلقائي الترقيم, نحتاج لتحديث الخاصية AutoIncrementSeed كي تبدأ عند أكبر معرف تسجيل للجدول UserInfo موجود على قاعدة البيانات حتى يكون هناك تزامن بين معرف التسجيل على الذاكرة الحية و بين التسجيل على قاعدة البيانات. التزامن هنا تقريبي لعدة عوامل, أولها أنه للحصول على آخر معرف تلقائي الترقيم يجب قبله القيام بعملية زيادة تسجيل على الجدول على قاعدة الباينات حتى نحصل على نتيجة صحيحة عن طريق تنفيذ استعلام لـ @@IDENTITY التي ترجع 0 في الحالة المعاكسة. مرجع التسجيلات الموجودة على الذاكرة الحية سيكون أقرب إلى الحقيقة بعد زيادة أول تسجيل و حفظ على قاعدة البيانات بعد إعادة تشغيل التطبيق.


الكود:

' الحصول على أكبر مرجع للتسجيلات لاستعماله في حساب مرحع التسجيلات
 ' الموجودة على الذاكرة الحية
 If BindingContext(MyDataSet, "UserInfo").Count > 0 Then
 ' الحصول على أكبر معرف في الجدول
 Dim rows() As DataRow = MyDataSet.Tables("UserInfo").Select("MAX(ID)=ID")
 ' حفظ المرجع للاستعمال
 MyDataSet.Tables("UserInfo").Columns("ID").AutoIncrementSeed = rows(0)("ID") + 1
 End If



التحرك بين التسجيلات :
الآن و قد تم تحميل البيانات من قاعدة البيانات إلى الذاكرة الحية. سنلاحظ و كما هو ضاهر في الصورة أعلاه وجود معلومات عن مستخدم واحد فقط عكس مارأيناه في الجزئين السابقين على مربع الداتاجريدفيو التي تعرض جميع التسجيلات مرة واحدة. لتمكين المستخدم من استعراض جميع الجداول, قمنا بزيادة أزرار أعلى النموذج للتحرك إلى التسجيل الأول, الأخير, السابق و اللاحق. عملية التحرك إلى تسجيل معين تتم غالبا عن طريق تحديد رقم التسجيل في الخاصية Position للكائن من فئة BindingManagerBase :


الكود:

' الوصول إلى أول تسجيل
 Me.BindingContext(MyDataSet, "UserInfo").Position = 0

 ' الوصول إلى التسجيل السابق
 Me.BindingContext(MyDataSet, "UserInfo").Position -= 1

 ' الوصول إلى التسجيل اللاحق
 Me.BindingContext(MyDataSet, "UserInfo").Position += 1

 ' الوصول إلى آخر تسجيل
 Dim mngr As BindingManagerBase = Me.BindingContext(MyDataSet, "UserInfo")
 mngr.Position = mngr.Count - 1



زيادة تسجيل جديد :
في الوضع المنفصل, يتم التعامل مباشرة مع التسجيلات DataRow الموجودة على الذاكرة الحية لعمليات الزيادة, التحديث و الحذف و لكن عملية ربط مربعات التحكم بالحقول تعفينا من التعامل المباشر مع كائنات DataRow حيث تقوم الفئة BindingManagerBase بعمل التحديث المتزامن للبيانات الموجودة على مربعات التحكم للنموذج مع التسجيلات DataRow.
في الحالات العادية, المناداة على الدالة BindingManagerBase.AddNew كفيلة وحدها لزيادة تسجيل جديد DataRow على الجدول DataTable. في بعض الحالات, يحتاج التسجيل إلى تهيئة خاصة قبل زيادته إلى الجدول. لتشخيص عملية زيادة تسجيل جديد, نقوم أولا بالحصول على تسجيل جديد أي كائن من فئة DataRow للتسجيل الجديد عن طريق المناداة على الدالة NewRow للجدول DataTable المراد زيادة تسجيل جديد فيه. كائن DataRow الذي تم إرجاعه له بنية تسجيل من نوع تسجيلات الجدول DataTable من عدد الحقول و نوع قيمة كل حقل و غيره :


الكود:

 ' الحصول على تسجيل جديد على الذاكرة الحية
 Dim row As DataRow = MyDataSet.Tables("UserInfo").NewRow()


بعد ذلك, نقوم بتنفيذ أمر بدء تحرير حقول التسجيل row :


الكود:

 ' طلب بدء عملية تحرير حقول التسجيل
 row.BeginEdit()


بعد ذلك, نستطيع تحديد المحتوى الافتراضي لكل حقل من حقول التسجيل الجديد :


الكود:

 ' تحديد المحتوى الأولي للحقول
 row("Login") = "<Login_" + row("ID").ToString() + ">"
 row("Password") = "<Password_" + row("ID").ToString() + ">"
 row("GroupID") = 1



بعد عملية تحرير محتوى حقول تسجيل DataRow, نكمل العملية بالمناداة على الدالة EndEdit :


الكود:

 ' أمر إنهاء عملية التحرير
 row.EndEdit()



حتى الآن, التسجيل الذي قمنا بتهيئته لا ينتمي إلى أي جدول. لزيادته إلى الجدول DataTable نقوم بزيادته إلى مجموعة تسجيلات الجدول عن طريق المناداة Add للخاصية Rows للجدول المراد زيادة التسجيل إليه :


الكود:

 ' زيادة التسجيل الجديد إلى الجدول على الذاكرة الحية
 MyDataSet.Tables("UserInfo").Rows.Add(row)



يجب الانتباه إلى أن التسجيل تمت زيادته في آخر مجموعة تسجيلات الجدول, لذا سنحتاج إلى الانتقال إلى آخر تسجيل لتمكين المستخدم من بدء تحرير محتوى التسجيل :


الكود:

' التسجيل الجديد تتم زيادته في آخر الجدول
 ' لذا نصل إلى آخر تسجيل
 GoLastButton.PerformClick()


للحؤول دون كتابة كود زيادة مثل هذا, نستطيع تحديد قيمة افتراضية لكل حقل وقت زيادة الحقل على البرنامج مسير قواعد البيانات كـ Access أو SQL Server Management Studio أو غيره حتى نستطيع زيادة تسجيل جديد بأقل عدد ممكن من أسطر الكود.

تحديث تسجيل :
بالنسبة لعملية تحديث التسجيلات, الكائن الذي يقوم بالتحديث المتزامن للبيانات يقوم بالعمل كله. عندما تقوم بتغيير محتوى مربع مرتبط بحقل يقوم الكائن من فئة BindingManagerBase بتحديث محتوى الحقل المرتبط بالمربع على التسجيل الحالي DataRow أوتوماتيكيا قبيل الانتقال إلى مربع تحكم آخر أي بعد أو عند حدث التأكد من محتوى المربع Validated. و عند التحرك إلى تسجيل آخر, يقوم نفس الكائن بتحديث محتوى المربعات بمحتويات الحقول المرتبطة بها للتسجيل الذي تم الوصول إليه.

حذف تسجيل :
عملية حذف تسجيل من الجدول الموجود على الذاكرة الحية عملية بسيطة بساطة التطبيق الذي نحن بصدد دراسته الآن. يكفي المناداة على الدالة RemoveAt للكائن من فئة BindingManagerBase و تمرير رقم التسجيل DataRow المراد حذفه حتى تتم العملية :


الكود:

Dim mngr As BindingManagerBase = BindingContext(MyDataSet, "UserInfo")
 ' خروج إذا لم تكن هناك تسجيلات على الجدول على الذاكرة الحية
 If mngr.Count <= 0 Then Return
 ' حذف التسجيل الحالي من الجدول الموجود على الذاكرة الحية
 mngr.RemoveAt(mngr.Position)



حفظ البيانات :
بعد القيام بعمليات الزيادة, الحذف و التحديث حسب متطلبات العمل نحتاج إلى حفظ البيانات من الذاكرة الحية رجوعا نحو قاعدة البيانات. الكود هو نفسه الذي سبق و درسناه في الجزء الأول. نقوم أولا بالتحقق من وجود تغييرات على البيانات الموجودة على الذاكرة الحية. في حالة وجودها, نقوم بالتأكد من قيمة مربع التحكم الحالي ثم نقوم بإنهاء عملية تحرير التسجيل الحالي و في الأخير, نقوم بعملية الحفظ :


الكود:


 ' إذا كانت هناك تغييرات على البيانات الموجودة على الذاكرة الحية
 If MyDataSet.HasChanges() Then
 ' نطلب التحقق من المعلومات المكتوبة على مربعات النموذح
 Me.Validate()
 ' إنهاء تحرير التسجيل الحالي الموجود على الذاكرة الحية
 Me.BindingContext(MyDataSet, "UserInfo").EndCurrentEdit()
 ' حفظ البيانات الموجودة على الجدول على الذاكرة الحية
 ' رجوعا نحو الجدول على قاعدة البيانات
 MyAdapter.Update(MyDataSet.Tables("UserInfo"))
 End If



الكود أعلاه يتم تنفيذه عند الضغط على الزر Save و ستجدون على المشروع المرفق أنه يتم تنفيذ نفس الكود عند غلق التطبيق بعد أخد موافقة المستخدم.


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