مثال
على علاقة ذاتية بين الجدول ونفسه Self-Relation:
سنرى
الآن مثالا على العلاقة الذاتية Self-Relation.. لفعل هذا، سننشئ مشروعا اسمه SaveTreeNodes، وهو يعرض شجرة ويسمح للمستخدم إضافة العناصر إليها، وتغيير مستوياتها،
وهي وظائف تعلمنا كيف ننشئها في المشروع TreeViewSample في كتاب "من الصفر
إلى الاحتراف: برمجة نماذج الويندوز"، ولن نكرر شرحها هنا.. وستجد
المشروع SaveTreeNodes ضمن أمثلة هذا الكتاب.
ما
نريده هو أن نسمح للمستخدم بحفظ فروع الشجرة.. لا نحتاج هنا إلى إنشاء قاعدة
بيانات كاملة لمجرد حفظ بعض عناصر الشجرة، فمن الممكن أن ننشئ مجموعة بيانات خاصة Custom
DataSet، ونستخدمها لحفظ العناصر
في ملف XML.. وبهذا نكون قد استفدنا من قدرات مجموعة البيانات وعلاقاتها، وفي
نفس الوقت سنحفظ البيانات في ملف مستقل.
لفعل
هذا، أضفنا إلى المشروع SaveTreeNodes
مخطط مجموعة بيانات بالطريقة المألوفة، وأسميناه TreeDataSet، وأضفنا إليه جدولا اسمه TreeNodes، وأضفنا إليه الأعمدة التالية:
اسم
العمود
|
نوع
بياناته
|
وظيفته
|
ID
|
Int16
|
المفتاح
الأساسي، وهو يعمل أيضا كترقيم تلقائي.
|
Text
|
String
|
يحفظ
نص فرع الشجرة.
|
ParentID
|
Int16
|
المفتاح
الفرعي، وهو يشير إلى رقم الفرع الرئيسي للفرع الحالي.
|
وقد
أضفنا علاقة إلى مخطط الجدول، لتربط بين الحقلين ID و ParentID.
هكذا
يبدو شكل المخطط.. لاحظ في الصورة كيف تخرج العلاقة من نفس الجدول وتعود إليه.
وقد
أضفنا إلى النموذج نسخة من مجموعة البيانات وأسميناها TreeDs كما فعلنا في الفقرة السابقة.. وحتى لا نعقد الأمور على أنفسنا، لن نملأ
مجموعة البيانات بعناصر الشجرة إلا عند ضغط زر الحفظ، فهي مجرد وعاء وسيط يتيح لنا
حفظ البيانات في ملف XML..
هذا هو كود هذا الزر:
TreeDs.Clear( )
For Each Node As TreeNode In
TreeView1.Nodes
Dim R =
TreeDs.TreeNodes.AddTreeNodesRow(
Node.Text, Nothing)
SaveChildren(Node,
R)
Next
TreeDs.WriteXml("C:\TreeNodes.Xml")
في
البداية أفرغنا مجموعة البيانات من محتوياتها، ثم مررنا عبر جذور الشجرة لإضافتها
إلى الجدول TreeNodes
الموجود في مجوعة البيانات.. لاحظ أن مجموعة البيانات محددة النوع قد أضافت
الوسيلة AddTreeNodesRow إلى الجدول، لتتيح لنا إضافة صف جديد إليه.. هذه الوسيلة تستقبل
معاملين:
- نصا يمثل قيمة الحقل Text في الصف الجديد.
- كائن صف من النوع TreeDataSet.TreeNodesRow، لترسل إليه الصف الرئيسي للصف الحالي.. هذا أسهل من أن تضع بنفسك
رقم الصف الرئيسي في الحقل ParentID، وهذه إحدى التسهيلات التي منحتها لك العلاقة الذاتية.. ونظرا لأن
جذور الشجرة ليست لها فروع رئيسية، فسنرسل القيمة Nothing إلى هذا المعامل.. هذا سيترك الحقل ParentID فارغا.
بعد
هذا، يجب أن نضيف إلى مجموعة البيانات فروع كل جذر، بكتابة إجراء اسمه SaveChildren، وهو يستقبل معاملين:
- كائن الفرع TreeNode الذي سنضيف عناصره الفرعية إلى مجموعة البيانات.
- كائن الصف TreeDataSet.TreeNodesRow الذي يعمل كصف رئيسي، للصفوف التي سنضيفها الجدول.
هذا
هو كود هذا الإجراء، مع ملاحظة أنه إجراء ارتدادي Recursive يستدعي نفسه، لأن كل فرع قد يحتوي على عناصر فرعية، كل منها قد
يحتوي على عناصر فرعية، وهكذا:
Sub SaveChildren(ByVal ParentNode As
TreeNode,
ByVal ParentRow As
TreeDataSet.TreeNodesRow)
For Each Node As
TreeNode In ParentNode.Nodes
Dim R =
TreeDs.TreeNodes.AddTreeNodesRow(
Node.Text,
ParentRow)
SaveChildren(Node, R)
Next
End Sub
وبعد
وضع جميع بيانات الفروع في مجموعة البيانات، سيتم تنفيذ آخر سطر في كود ضغط زر
الحفظ، وهو يستدعي الوسيلة WriteXML لحفظ محتويات مجموعة البيانات في الملف.
وهكذا
نكون قد حفظنا فروع الشجرة بالكامل.. بقي إذن أن نعيد قراءتها من الملف عند ضغط زر
التحميل.. لفعل هذا سنفرغ كلا من مجموعة البيانات والشجرة من محتوياتهما، ثم نقرأ
بيانات الملف باستخدام الوسيلة ReadXML:
TreeDs.Clear( )
TreeView1.Nodes.Clear( )
TreeDs.ReadXml("C:\TreeNodes.Xml")
بعد
هذا سننقل البيانات من مجموعة البيانات إلى الشجرة.. لفعل هذا سنضيف الجذور إلى
الشجرة أولا.. نحن نعرف أن الجذر ممثل في الجدول بصف توجد في الخانة ParentID الخاصة به القيمة DbNull.. لهذا سنمر على كل الصفوف، ونستخدم الوسيلة الجاهزة IsParentIDNull التي عرفتها لنا مجموعة البيانات محددة النوع، لنرى إن كانت هذه
الخانة فارغة، فإن كانت كذلك، عرفنا فرعا جديدا، ووضعنا فيه النص الموجود في
الخانة Text، وأضفناه إلى الشجرة كجذر، ثم نستدعي الإجراء LoadChildren لتحميل العناصر الفرعية في هذا الجذر.. هذا هو الكود الذي يفعل
هذا:
For Each R In TreeDs.TreeNodes
If
R.IsParentIDNull Then
Dim Node =
TreeView1.Nodes.Add(R.Text)
LoadChildren(Node, R)
End If
Next
أيضا،
يجب أن يكون الإجراء LoadChildren
ارتداديا Recursive
يستدعي نفسه، لتحميل العناصر الفرعية لكل فرع في جميع المستويات.
ولكن
كيف نعرف العناصر الفرعية؟
هذا
سهل جدا، بفضل العلاقة الذاتية المعرفة في الجدول، واستخدام الوسيلة GetChildRows لمعرفة الصفوف الفرعية التابعة لأي صف رئيسي.. هذا هو كود هذا الإجراء:
Sub LoadChildren(ByVal ParentNode As
TreeNode,
ByVal ParentRow As
TreeDataSet.TreeNodesRow)
For Each R As
TreeDataSet.TreeNodesRow In
ParentRow.GetChildRows("Self_Relation")
Dim Node
= ParentNode.Nodes.Add(R.Text)
LoadChildren(Node, R)
Next
End Sub
هذا
هو كل شيء.. يمكنك الآن تجربة البرنامج، وإضافة العناصر إلى الشجرة، وحفظها، ثم
استرجاعها في أي وقت.
رائعة
هي العلاقة الذاتية؟.. أليس كذلك؟
من
كتاب: من الصفر إلى الاحتراف برمجة قواعد البيانات في فيجوال بيزيك دوت نت ADO .NET.. للتنزيل:
ليست هناك تعليقات:
إرسال تعليق
ملحوظة: يمكن لأعضاء المدونة فقط إرسال تعليق.