شاطر
اذهب الى الأسفل
عدد المساهمات : 134
تاريخ التسجيل : 08/10/2012
معاينة صفحة البيانات الشخصي للعضو

الوضع المتصل والوضع المنفصل-ربط DataGridView بجدول في الوضع المتصل

في الخميس أكتوبر 10, 2013 5:50 pm


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

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

كما رأينا معا سابقا, استعملنا الجداول DataTable و الحاوية DataSet و OleDbDataAdapter لتحميل البيانات في الوضع المنفصل. في الوضع المتصل, لن نستعمل أيا من هذه الفئات, سنستعمل بدلا منها الفئة OleDbDataReader لتحميل البيانات من القاعدة لأن الفئة OleDbDataReader لها بنية خاصة للاستعمال في الوضع المتصل بتحميله التسجيلات واحدا واحدا من الجدول عند المناداة على الدالة Read. أما بالنسبة لعمليات الزيادة, التحديث و الحذف فستتم مباشرة على قاعدة البيانات بالتوازي مع حدوثها على الداتاجريدفيو.

تعريفات :
لمعرفة حالة السطر الحالي للداتاجريدفيو, سنحتاج إلى توابث لتحديد حالة السطر, الأول RowAdded وقت زيادة سطر جديد و الثاني RowEdited وقت تحديث محتوى خلية :


الكود:

' لتعليم سطور الداتاجريدفيو على أنها تمت زيادتها
  Private Const RowAdded As Integer = 1
  
  ' لتعليم سطور الداتاجريدفيو على أنها تمت تحرير محتوياتها
  Private Const RowEdited As Integer = 2


لتنفيذ جمل SQL, سنحتاج لكائن من نوع OleDbConnection لفتح وغلق قناة الإتصال بقاعدة البيانات و قت الحاجة :


الكود:

' كائن الربط
  Private MyConnection As OleDbConnection



التعريفات السابقة كلها معرفة على مستوى النموذج Form لأننا سنحتاج إليها طول وقت تنفيذ التطبيق.

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


الكود:

إنشاء و تهيئة كائن الربط
  MyConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source =.\AccessDB.mdb")


بعد ذلك, سنقوم بتحميل أسماء المجموعات من الجدول GroupInfo إلى جدول على الذاكرة الحية لربطه بعد حين بعمود من نوع DataGridViewComboBoxColumn الذي سيمكن المستخدم من اختيار مجموعة من المجموعات على اللائحة على الكومبوبوكس التي تظهر مكان خلايا العمود :


الكود:

' تحميل جدول المجموعات
  Dim cmd As New OleDbCommand("SELECT * FROM GroupInfo", MyConnection)
  Dim tbl As New DataTable("GroupInfo")
  MyConnection.Open()
  tbl.Load(cmd.ExecuteReader())



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

بعد ذلك سنقوم بإنشاء كائن من نوع OleDbCommand و تهيئته بجملة استعلام لتحميل البيانات من القاعدة :


الكود:

' تحميل جدول المستخدمين
  cmd = New OleDbCommand("SELECT * FROM UserInfo", MyConnection)


بعد ذلك سنقوم بتنفيذ جملة الاستعلام بالمناداة على الدالة ExecuteReader التي سترجع لنا كائن من نوع OleDbDataReader الذي سيمكننا من التعرف على اسماء حقول الجدول و كذلك قراءة التسجيلات التي تم إيجادها على قاعدة البيانات :


الكود:


' تحميل جدول المستخدمين تسجيل بعد تسجيل
  Dim rdr As OleDbDataReader = cmd.ExecuteReader()


بعد ذلك سوف نقوم بقراء اسماء حقول الجدول و زيادة عمود لكل حقل على الداتاجريدفيو :


الكود:

' إذا كانت هناك حقول على الجدول
  If rdr.FieldCount <> 0 Then
  ' إنشاء عمود لكل جدول
  For i As Integer = 0 To rdr.FieldCount - 1
  Dim fld As String = rdr.GetName(i)
  If fld <> "GroupID" Then
  ' زيادة العمود
  DataGridView1.Columns.Add(fld, fld)
  Else ' عمود خاص بجدول الكومبوبوكس به لائحة المجموعات
  Dim cmb As New DataGridViewComboBoxColumn()
  cmb.HeaderText = fld
  ' ربط جدول المجموعات بخلايا العمود من نوع كومبوبوكس
  cmb.DataSource = tbl
  cmb.DisplayMember = "Name"
  cmb.ValueMember = "ID"
  ' زيادة العمود
  DataGridView1.Columns.Add(cmb)
  End If
  Next
  ' العمود الأول لحقل تلقائي الترقيم فلا يجب تحريره من طرف المستخدم
  DataGridView1.Columns(0).ReadOnly = True
  End If


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

بعد زيادة الأعمدة, نستطيع زيادة اسطر البيانات التي ستتم قرائتها بالتوازي مع عملية الزيادة على الداتاجريدفيو. الوضع المتصل بالطبع. الكود :


الكود:

' إذا كانت هناك سطور بالجدول
  If rdr.HasRows Then
  ' قراءة السطر التالي من الجدول من قاعدة البيانات
  While rdr.Read()
  ' زيادة السطر على الداتاجريدفيو
  Dim row As DataGridViewRow = DataGridView1.Rows(DataGridView1.Rows.Add())
  ' إحالة محتوى الحقل إلى محتوى الخلية المناسبة
  For i As Integer = 0 To rdr.FieldCount - 1
  row.Cells(i).Value = rdr.GetValue(i)
  Next
  End While
  End If


عند هذه النقطة, سنقطع الاتصال بقاعدة البيانات و نترك المستخدم يقوم بعمله على أسطر الداتاجريدفيو. كل عملية تتم على مستوى سطر ما من أسطر الداتاجريدفيو, سيتم تنفيذ جملة سكل الخاصة بها عندما ينتقل المستخدم من سطر إلى آخر...


زيادة سطر جديد/تسجيل جديد :
عندما يقوم المستخدم بالكتابة على السطر الأخير من الداتاجريدفيو, تقوم هذه الأخيرة بالمناداة على دالة الحدث UserAddedRow حيث سنقوم بتعليم السطر الجديد بتابث RowAdded بإحالته إلى الخاصية Tag للكائن الذي يمثل السطر داخل مجموعى أسطر الداتاجريدفيو Rows :


الكود:


' إلتقاط حدث زيادة سطر جديد على الداتاجريدفيو
  Private Sub DataGridView1_UserAddedRow(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowEventArgs) Handles DataGridView1.UserAddedRow
  ' تعليم السطر على أنه تمت زيادته
  DataGridView1.Rows(e.Row.Index - 1).Tag = RowAdded
  End Sub


عملية زيادة السطر الجديد إلى الجدول على قاعدة البيانات ستتم بعدما ينتهي المستخدم من تحرير محتوى خلايا السطر ثم يقرر الانتقال إلى سطر آخر, في هذا الوقت, ستقوم الداتاجريدفيو بالمناداة على دالة الحدث RowValidating حيث سنقوم بزيادة السطر الجديد بعد فتح قناة الاتصال بقاعدة البيانات :


الكود:

' إنشاء و تهيئة كائن تنفيذ جملة سكل
  Dim cmd As New OleDbCommand("INSERT INTO UserInfo ([Login], [Password], GroupID) VALUES(@Login, @Password, @GroupID)", MyConnection)
  ' زيادة و تهيئة الوسائط بأسماء الحقول و قيمها من السطر الحالي على الداتاجريدفيو
  cmd.Parameters.Add("@Login", OleDbType.WChar, 32, "Login").Value = row.Cells(1).Value
  cmd.Parameters.Add("@Password", OleDbType.WChar, 32, "Password").Value = row.Cells(2).Value
  cmd.Parameters.Add("@GroupID", OleDbType.BigInt, 1, "GroupID").Value = row.Cells(3).Value
  ' تنفيذ جملة سكل
  n = cmd.ExecuteNonQuery()


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


الكود:

' الحصول على مرجع التسجيل
  cmd.CommandText = "SELECT @@IDENTITY FROM UserInfo"
  row.Cells(0).Value = cmd.ExecuteScalar()



سنحتاج إلى الحصول على مرجع التسجيل الجديد حتى نتمكن من تمريره لكود الحذف الذي يعتمد عليه لتمييز التسجيل المراد حذفه.

حذف سطر/تسجيل :
عندما يقوم المستخدم بالنقر على رأس سطر Row header تقوم الداتاجريدفيو بتحديد السطر كاملا و يكفي من المستخدم الضغط على الزر Delete من لوحة المفاتيح حتي يتم حذف السطر كاملا. قبيل تنفيذ عملية حذف السطر, ستقوم الداتاجريدفيو بالمناداة على دالة الحدث UserDeletingRow حيث سنقوم بالحصول على مرجع السطر المراد حذفه ثم نقوم بحذف التسجيل المعرف بنفس المعرف من الجدول على قاعدة البيانات :


الكود:

' إنشاء و تهيئة أمر سكل
  Dim cmd As New OleDbCommand("DELETE FROM UserInfo WHERE ID=@ID", MyConnection)
  ' مرجع التسجيل الذي سيتم حذفه
  cmd.Parameters.Add("@ID", OleDbType.BigInt, 1, "ID").Value = e.Row.Cells(0).Value
  ' فتح قناة الاتصال
  MyConnection.Open()
  ' تنفيذ جملة سكل
  Dim n As Integer = cmd.ExecuteNonQuery()
  ' غلق قناة الاتصال
  MyConnection.Close()
  ' تحرير الكائن
  cmd.Dispose()



تحديث سطر/تسجيل :
عندما يقوم المستخدم ببدء الكتابة على خلية ما, ستقوم الداتاجريدفيو بالمناداة على دالة الحدث CellEndEdit حيث سنقوم بتعليم السطر الحالي على أنه تم تحديث محتواه عن طريق إحالة التابث RowEdited إلى الخاصية Tag للكائن الممثل للسطر إذا لم يكن معلم مسبقا على أنه سطر جديد في هذه الحالة نترك السطر بعلامة سطر جديد حتى لا يرفع استثناء بسبب محاولة تحديث سطر غير موجود على الجدول على قاعدة البيانات :


الكود:

' تعليم السطر الذي تم تغيير قيمة خليته على أنه تم تحديث محتواه
  Private Sub DataGridView1_CellEndEdit(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
  ' حتى لا يتم تغيير علامة الزيادة بعلامة التحديث
  If DataGridView1.Rows(e.RowIndex).Tag Is Nothing Then
  ' تعليم السطر على أنه تم تحديته
  DataGridView1.Rows(e.RowIndex).Tag = RowEdited
  End If
  End Sub



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


الكود:

' إنشاء و تهيئة كائن تنفيذ جملة سكل
  Dim cmd As New OleDbCommand("UPDATE UserInfo SET [Login] = @Login, [Password] = @Password, GroupID = @GroupID WHERE ID = @ID", MyConnection)
  ' زيادة و تهيئة الوسائط بأسماء الحقول و قيمها من السطر الحالي على الداتاجريدفيو
  cmd.Parameters.Add("@Login", OleDbType.WChar, 32, "Login").Value = row.Cells(1).Value
  cmd.Parameters.Add("@Password", OleDbType.WChar, 32, "Password").Value = row.Cells(2).Value
  cmd.Parameters.Add("@GroupID", OleDbType.BigInt, 1, "GroupID").Value = row.Cells(3).Value
  ' مرجع التسجيل الذي سيتم تحديته
  cmd.Parameters.Add("@ID", OleDbType.BigInt, 1, "ID").Value = row.Cells(0).Value
  ' تنفيذ جملة سكل
  n = cmd.ExecuteNonQuery()


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

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


_________________
[img][ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذا الرابط] [/img]
الرجوع الى أعلى الصفحة
صلاحيات هذا المنتدى:
لاتستطيع الرد على المواضيع في هذا المنتدى