بســـــــــــم الله الرحمن الرحيم
السلام عليكم و رحمة الله و بركاته
ابدأ معكم بمراجعة بسيطة بطرق تعاملنا مع الجداول وفق تقنية ADO.Net و اهم العمليات التي نحتاجها بشكل متكرر اثناء عملنا مع اي جدول , لا يخفى على الجميع و الكل يعرف اننا دائما و ابداً نحن امام الحالات التقليدية (الاضافة و التعديل و الحذف) كحالات رئيسة ترافق العمل مع اي جدول بالاضافة للحالات الاخرى حسب الحاجة من عمليات البحث او تجميع البيانات وفق اي نوع من الاستعلامات تفرضه علينا الحاجة .
و اعتدنا دائماً على التعامل مع الجمل التقليدية التي توافق كل حالة و على اعادة تكرارها مع كل مشروع .
و الذي يختلف فقط هو عدد الحقول و اسمائها و انواع بيانات الحقول فيها .
و هذا التكرار اشبه بعملية النسخ و اللصق و تغير ما يلزم وفق المعطيات التي يحملها المشروع الجديد
هذه المقدمة البسيطة ضرورية لنتجاوز التكرار او بالمختصر لنحول عملية النسخ و اللصق المعتادة الى طريقة عملية تجعلنا نستفيد من الثوابت في جمل الادخال و الاضافة و التعديل و البحث و غيرها من الجمل و نحولها الى دوال منفصلة نحتاج فيها فقط ما يتغير مع كل مشروع جديد , و بالتالي نفصلها في فئة خاصة بها بعيداً عن واجهة البرنامج (مثل مكتبة او اطار عمل) و عند حاجتنا لها نستدعي المكتبة و نغير فقط ما يسمح لنا بتغيره و بالتالي وفرنا على انفسنا عناء اعادة كتابة الجمل كل مرة.
و من جهة اخرى و هي الباب الثاني في الموضوع اننا نتعامل مع جدول عبارة عن كائن منفصل يحتوي على حقول محددة , و هذه الحقول هي التي ستقوم عليها العمليات السابقة , بالاضافة لاي عمليات اخرى قد تحتاجها على هذا الكائن لذا ارى انه من الافضل ان تكون هذه العمليات الخاصة بهذا الكائن حكراً عليه و ان رايت ان اكثر من كائن يمكن ان يتشارك في هذه العملية يمكنك جعلها في المكتبة الرئيسية كدالة عامة يمكن لاي كائن ان يستدعيها و يطبقها و فق خصوصيته.
و على هذا فان عمليات الاضافة و التعديل و الحذف ممكن ان نجعل لها اكثر من نسخة في المكتبة نسخة خاصة و نسخة عامة
النسخة الخاصة يعاد تطبيقها في اي كائن يستدعيها و يتم تغير المعطيات وفق حاجتنا
اما النسخة العامة فيمكن تمريرها بشكل مباشر لاي كائن دون الحاجة للتغيير فيها
اتمنى ان يكون كلامي مفهوم الى هذه اللحظة و ان شاء الله سيتضح مع التطبيق الذي سنبدئه و نناقش تطويره
في البداية ساعرض جملة الادخال المعروفة لديكم لنرى ما هي الثوابت فيها , ووفق شكلها القياسي التالي
PHP كود :
INSERT INTO table_name (column1,column2,column3,...)
VALUES (value1,value2,value3,...)
و على هذا لو كان لدي مصفوفة من الاعمدة و القيم تمرر بدل هذه المتغيرات اكون قد ارتحت من اعادة كتابة نفس الجملة
هذا من طرف الجملة , اما من طرف اطار العمل سيكون لدي كائن يقوم بتنفيذ هذه الجملة و هذا الكائن يحتاج الى اتصال و يحتاج الجملة السابقة و يحتاج الى بارمترات موافقة لعدد الحقول و قيم لهذه البارمترات و في النهاية سيقوم بالتنفيذ بعد اكتفائه بالمعلوممات المطلوبة.
الان لننظر الى هذا الكود الخاص بهذا الكائن و لنكتشف ما يمكننا الاستفادة منه
كائن ينفذ عملية ادخال سجل جديد في جدول
PHP كود :
Private Sub Insert_SomeData()
Dim Insert_Statement As String = "INSERT INTO table_name (column1,column2,column3) VALUES (@column1, @column2, @column3)"
Using Cmd As New SqlClient.SqlCommand(Insert_Statement, Con)
Cmd.Parameters.AddWithValue("@column1", Txt_column1.Text)
Cmd.Parameters.AddWithValue("@column2", Txt_column2.Text)
Cmd.Parameters.AddWithValue("@column3", Txt_column3.Text)
Con.Open()
Cmd.ExecuteNonQuery()
Con.Close()
End Using
End Sub
اذاً ما علينا في هذه الحالة ان نمرر اسم الجدول كبارميتر لهذا الاجراء و كذلك نمرر اسماء الحقول و قيمها ايضاً كبارميتر عبر مصفوفة و نكون قد تحصلنا على اجراء ادخال عام يستطيع الادخال في اي جدول بمجرد استدعائه و تمرير وسائطه المطلوبة
و لو دققنا اكثر في الاجراء السابق الخاص بالاضافة سنرى انه ينفذ عملية في داخله و هي ExecuteNonQuery و التي بدورها تعيد قيمة رقمية بعد تنفيذها فهي تعيد اما 0 او 1 نجاح او فشل التنفيذ و عليه يمكننا استغلال الرقم العائد و عرض رسالة في حال نجح او فشل , و عليه فاننه يمكننا تحويل الاجراء السابق الى دالة تعيد الرسالة .
و بمنطق اعمق , بما انني اضيف سجل جديد و فق الدالة السابقة فالاولى ان اتحصل على رقم السجل المضاف الى الجدول لاستفيد منه و بناءً على ذلك اريد ان اجري عملية اضافية بعد الادخال و هي تحصيل رقم السجل و فق الكود التالي
PHP كود :
Cmd.CommandText = "Select @@IDENTITY"
Resuilt = CType(Cmd.ExecuteScalar(), Integer)
الى هنا ينتهي غرضي من هذا التقديم لانتقل بك الى الجزء التالي
السيناريو الذي ساعمل عليه هو فتح كلاس جديد على مستوى المشروع سنقوم بادراج دوال عامة للتعامل مع العمليات السابقة مع شرح مبسط لبعضها لان الفكرة العامة قد تم شرحها باختصار في الاعلى , و بعدها سنتعامل مع قاعدة بيانات من جدولين اب و ابن
و سنخصص كلاسات تمثل كل جدول و في كل كلاس سنغلف العمليات التي تجري على هذا الكائن بعد ان نرثها من الكلاس الرئيسي و نخصصها حسب الكائن , و بعدها سننشاً نموذجنا يتخاطب مع هذه الكلاسات و يقوم بالعمليات المطلوبة .
يتبع...
في البداية ننشأ مشروع جديد
نضيف كلاس للمشروع و نسميه DbGo او سميه ما شئت ستكون وضيفة هذا الكلاس تجميع كل ما نحتاجه من دوال و اجراءات عامة يمكن لكل الكائنات ان تستفيد منها و تعيد تطبيقها بما يناسبها
ساضيف لهذا الكلاس بعض التمهيدات الاولية كما يلي
PHP كود :
Protected Shared MyConnectionString As String = ""
Protected Shared ConSql As New SqlClient.SqlConnection(MyConnectionString)
Shared Sub New(ByVal ConnectionString As String)
SetConnectionString = ConnectionString
If ConSql.ConnectionString = Nothing Then ConSql.ConnectionString = MyConnectionString
End Sub
عند انشاء اي نسخة جديدة منه سيطلب منك تمرير نص الاتصال الخاص بالسيرفر
PHP كود :
''' <summary>
''' Set Or Get ConnectionString
''' </summary>
''' <returns></returns>
Public Shared Property SetConnectionString() As String
Set(value As String)
MyConnectionString = value
End Set
Get
Return MyConnectionString
End Get
End Property
''' <summary>
''' Close Connection To Data Base
''' </summary>
Protected Shared Sub CloseConnect()
If ConSql.State = ConnectionState.Open Then
ConSql.Close()
End If
End Sub
''' <summary>
''' Open Connection To Datat Base
''' </summary>
Protected Shared Sub OpenConnect()
If ConSql.State = ConnectionState.Closed Then
If ConSql.ConnectionString = Nothing Then ConSql.ConnectionString = MyConnectionString
ConSql.Open()
End If
End Sub
خاصية لاسناد نص الاتصال او الحصول عليه و هي محصورة على الكائنات التي تشتق هذا الكلاس
اجراء لفتح الاتصال , و اجراء لغلق الاتصال
PHP كود :
''' <summary>
''' اضافة سجل جديد الى جدول
''' </summary>
''' <param name="TableName">اسم الجدول</param>
''' <param name="Table">الجدول الذي يحوي الحقول و قيمها وهو مصفوفة</param>
''' <param name="KeyFiled">اسم حقل المفتاح الرئيسي ليتم استثنائه من جملة الاضافة</param>
''' <param name="Msg">رسالة الاضافة وهي اختيارية</param>
''' <returns>يعود بقيمة الحقل المضاف للمفتاح الرئيسي</returns>
Protected Function Add_New(ByVal TableName As String, ByVal Table As Dictionary(Of String, Object), ByVal KeyFiled As String, Optional ByVal Msg As Boolean = False) As Integer
Dim Resuilt As Integer = 0
Dim Insert_Statement As String = "insert Into " & TableName & " ("
If Table.ContainsKey(KeyFiled) Then
Table.Remove(KeyFiled)
End If
Dim Column As String = String.Empty
For X As Integer = 0 To Table.Count - 1
Column = Table.Keys.ElementAt(X)
Insert_Statement += Column + ","
Next
'
If Insert_Statement.EndsWith(",") Then Insert_Statement = Insert_Statement.Remove(Insert_Statement.Count - 1, 1)
Insert_Statement += ")" & " Values ("
'
For X As Integer = 0 To Table.Count - 1
Column = Table.Keys.ElementAt(X)
Insert_Statement += "@" & Column + ","
Next
If Insert_Statement.EndsWith(",") Then Insert_Statement = Insert_Statement.Remove(Insert_Statement.Count - 1, 1)
Insert_Statement += ")"
'
OpenConnect()
Using Cmd As New SqlClient.SqlCommand(Insert_Statement, ConSql)
For i As Integer = 0 To Table.Count - 1
Cmd.Parameters.AddWithValue("@" + Table.Keys.ElementAt(i), Table.Values.ElementAt(i))
Next
For Each parm As SqlClient.SqlParameter In Cmd.Parameters
If IsNothing(parm.Value) Or IsDBNull(parm.Value) Then
parm.Value = DBNull.Value
End If
Next
Resuilt = Cmd.ExecuteNonQuery
'تحصيل رقم السجل
Cmd.CommandText = "Select @@IDENTITY"
Resuilt = CType(Cmd.ExecuteScalar(), Integer)
If Msg = True Then
If Resuilt > 0 Then
MessageBox.Show("تمت الاضافة بنجاح", "حفظ التعديلات", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
Else
MessageBox.Show("فشلت عملية الاضافة", "حفظ التعديلات", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
Resuilt = 0
End If
End If
End Using
CloseConnect()
Return Resuilt
End Function
شرح الدالة الخاصة بالاضافة
وسائط الدالة هي
TableName : اسم الجدول الذي سنتعامل معه
Table As Dictionary : جدول البيانات الذي سنتعامل معه و هو عبارة عن مصفوفه من النوع Dictionary تحتوي على عمودين واحد اخزن فيه اسماء الاعمدة و الثاني اخزن فيه قيمة كل عمود (ستتضح اليتها مع العمل و هي بسيطة جداً)
KeyFiled : اسم حقل المفتاح الرئيسي الخاص بالجدول ليتم استثنائه في عملية الاضافة
Msg : متغير منطقي (بولياني) اتحكم عن طريقه بعرض رسالة الاضافة من عدمها
PHP كود :
Dim Resuilt As Integer = 0
Dim Insert_Statement As String = "insert Into " & TableName & " ("
If Table.ContainsKey(KeyFiled) Then
Table.Remove(KeyFiled)
End If
Dim Column As String = String.Empty
For X As Integer = 0 To Table.Count - 1
Column = Table.Keys.ElementAt(X)
Insert_Statement += Column + ","
Next
PHP كود :
If Insert_Statement.EndsWith(",") Then Insert_Statement = Insert_Statement.Remove(Insert_Statement.Count - 1, 1)
Insert_Statement += ")" & " Values ("
'
For X As Integer = 0 To Table.Count - 1
Column = Table.Keys.ElementAt(X)
Insert_Statement += "@" & Column + ","
Next
If Insert_Statement.EndsWith(",") Then Insert_Statement = Insert_Statement.Remove(Insert_Statement.Count - 1, 1)
Insert_Statement += ")"
و نزيل بعدها الفاصلة الاخيرة و نكون بذلك قد كونا جملة اضافة لكل الحقول الموجودة في المصفوفة و التي تمثل حقول الجدول
PHP كود :
OpenConnect()
Using Cmd As New SqlClient.SqlCommand(Insert_Statement, ConSql)
For i As Integer = 0 To Table.Count - 1
Cmd.Parameters.AddWithValue("@" + Table.Keys.ElementAt(i), Table.Values.ElementAt(i))
Next
For Each parm As SqlClient.SqlParameter In Cmd.Parameters
If IsNothing(parm.Value) Or IsDBNull(parm.Value) Then
parm.Value = DBNull.Value
End If
Next
Resuilt = Cmd.ExecuteNonQuery
نضيف بارمترات لكائن الـ Command عبر المرور على عناصر المصفوفة حيث نضيف اسم البارمتر موافق لاسم الحقل و نعطيه القيمة المخزنة في العمود الثاني الخاص بقيمة العمود
بعدها نقوم بالمرور على بارمترات الكائن Command و نسند القيمة Null لكل القيم الفارغة ان وجدت حتى لا نقع في مشاكل الادخالات الفارغة
و اخيراً ننفذ عملية الاضافة
PHP كود :
'تحصيل رقم السجل
Cmd.CommandText = "Select @@IDENTITY"
Resuilt = CType(Cmd.ExecuteScalar(), Integer)
If Msg = True Then
If Resuilt > 0 Then
MessageBox.Show("تمت الاضافة بنجاح", "حفظ التعديلات", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
Else
MessageBox.Show("فشلت عملية الاضافة", "حفظ التعديلات", MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
Resuilt = 0
End If
End If
End Using
CloseConnect()
Return Resuilt
و سنفحص قيمة المتغير البولياني و على اساسه نعرض رسالة الاضافة
اخيراً نعود بقيمة السجل المضاف لنستفيد منها و نورثها للابناء
طبعاً كان بامكاننا الاستفادة من الدالة الخاصة بالموضوع السابق و نتحصل على رقم السجل الجديد قبل الاضافة , و لكن ليكون هناك تنوع بالطرق احببت السير بهذا الاتجاه
اتمنى ان تكون الدالة مفهومة و سهلة الادراك
يتبع...
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال