بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته،،
مرحباً بالأخوة جميعاً وأشكر كل من تفاعل مع الجزء الأول من هذه المقالة وأتمنى مزيد من المشاركات الإيجابية التي تضيف معلومة جديدة لهذه المقالة أو تصوب وتقوم ما أورد فيها.
المقدمة
أهلاً بكم في الجزء الثاني من العمل مع الإجراءات المخزنة Stored Procedures في Microsoft Access من خلالVB.NET. في الجزء الأول تناولنا بالشرح والتفصيل كَيفية إنشاء إجراءات مخزنةَ في Access باستخدام ADO.NET وVisual Basic.NET. في الجزء الثاني سنتناول كَيفَية استخدام الإجراءات المخزنةَ والتي قمنا بإنشائها في الجزء الأول من هذه المقالة بتجميع طبقة قاعدةِ البيانات والتي يمكن أَنْ تستخدمها كنموذج في التطبيقات الخاصة بك. هذه المقالة ستشرح بالتفصيل أحد تطبيقات طبقة قاعدة البيانات في Visual Basic.NET.
إن الغرض الرئيسي لطبقة قاعدةَ البيانات هو توفير مدخل إلى قاعدةِ البيانات من خلال صنفِ قياسي
class module. وهذا الصنف يقوم بدور الدمج بين قاعدةِ البيانات والتطبيقِ. واستخدام طبقة البيانات
data tier للوصول لقاعدة البيانات فائدتان رئيسيتان:
الأولى: هي القدرة على تبديل التقنيات التحتية لقواعد البيانات الخاصة بك مثلاً الإنتقال من MS Access إلى SQL Server دون أن يتأثر التطبيق الخاص بك بشكل كبير.
الثانية: إيجاد طبقة تحكم بين تطبيقِك وقاعدةِ البيانات وهذه الطبقة تمكنك من ضمان سلامة البيانات وتكاملها. في الغالب تشتمل طبقة قاعدة البيانات في تطبيقات NET. على وحدة صنفِ تلتزم بمعايير وإتفاقيات التشفيرالصحيح الموجه للكائنات object-oriented . في النسخ السابقة من 6Visual Basic وماقبلها استخدمت وحدة قياسية Standard Module للقيام بذلك.
كتابة الشفرة الخاصة بطبقة قاعدة البيانات
و الآن حان الوقت لتكشف عن ساعديك ونرفع أكمام ملابسك لتلوث يديك ببعض الكود.
أول شيء تقوم بعمله بعد إضافة ملف فارغ للإعلانِ عن الصنفِ هواستيراد مكتبات NET Framework. المناسبة كما تشاهد أدناه.
Imports System Imports System.Data Imports System.Data.OleDb
تعتبر المكتبةَ System مكتبة إفتراضية في أغلب التطبيقاتِ وبالنسبة لي شخضياً فأنني أقوم بتضمينها تقريباً في جميع وحدات الكود الخاصة بي .أما المكتبة System.Data فتعتبر ضرورية في جميع التطبيقات الخاصة بالتعامل والوصول لقواعد البيانات. وتستخدم المكتبة System.Data.OleDb حصرياً عند التعامل مع مزود OLEDB Database الخاص بـ Microsoft Access . أما في حال التعامل مع SQL Server فيجب أن تستخدم المكتبة الخاصة بمزودSQL وهي المكتبة System.Data.SqlClient.
السطر التالي من الشفرة يبدأ بتعريف الصنف:
Public Class DBTier
سمينا الصنف DBTier وأعلنا عنه كـ Public كي يصبح من السهل الوصول إليه مِن أي وحدات الكود الأخرى.
بعد تعريف الصنف يتم الإعلان عن كافة الخصائص:
Shared connectionString As String = _ "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program " _ & "Files\Microsoft Office\Office10\Samples\Northwind.mdb"
خاصية واحدة فقط تم الإعلان عنها كمتغير نصي string وهي الخاصية connectionString.
يحمل هذ المتغير سلسلة الإتصال بقاعدة البيانات Northwind.mdb وقد تم الإعلان عن هذا المتغير كـ Shared لتعريفه كـ"متغير صنف". متغير الصنف class variable مرتبط بالصنف ولَيسَ ككائن يمثل حالة مِنْ الصنف.
يلي الإعلانِ عن connection string ثلاثة إجراءات فرعية ودالة واحدة. الدالة ترجع dataset بقائمة بكافة المنتجات. وذلك من خلال استدعاء الإجراء المخزون procProductsList والذي تم إنشائه في الجزء الاول من هذه المقالة.
يلي ذلك ثلاثة إجراءات فرعية. إجراء فرعي مقابل كل إجراء مخزون( إضافة و تحديث وحذف المنتَجات). جميع الإجراءات كتبة بنفس الطريقة مع command و connection وإعلان عن البارامتر المطلوب.
كمثال دعنا نشرح الإجراء الفرعي ProductsDeleteItem . بعد استيعاب كيفية عمل هذا الإجراء الفرعي ستفهم بقية الإجراءات.
عند بدء الإجراء يستقبل بارامتر واحد هو ProductID من النوع عدد صحيح ويمثل رقم المنتج المطلوب حذفه.
Sub ProductsDeleteItem(ByVal ProductID As Integer)
يلي ذلك الإعلان عن كافة المتغيرات. التي تمثل الكائنات connection و command و parameter الذي سيمرر إلى الإجراءِ المخزونِ. هذا البارامتر يمثل ProductID للسجل المراد حذفه.
Dim con As OleDbConnection Dim cmd As OleDbCommand = New OleDbCommand() Dim paramProductID As New OleDbParameter()
يتم استهلال الكائنات Command و connection كالتالي :
con = New OleDbConnection(connectionString)
cmd.Connection = con
تقوم الأسطرالتالية بتهيئة وتشكيل خصائص البارامتر paramProductID. ثم تقوم بإضافته إلى كائن command. في هذه الحالة يكون اسم البارامتر في الإجراءِ المخزونِ هو inProductID ونوعه عدد صحيح والقيمة يحددها ProductID الممرر إلى هذا الإجراء.
With paramProductID .ParameterName = "inProductID" .OleDbType = OleDbType.Integer .Size = 4 .Value = ProductID End With cmd.Parameters.Add(paramProductID)
الجزء الأخير من هذا الإجراء يمثل الإستدعاء الفعلي للإجراء المخزون.
cmd.CommandText = "EXECUTE procProductsDeleteItem" con.Open() cmd.ExecuteNonQuery() con.Close()
لاحظ أن كائن connection يبقى مفتوحاً فقط لمدة تكفي لتَنفيذ الإجراءِ المخزونِ ثم يغلق فوراً. وهذا للتقليل من أي زيادة حمل محتملة.
في هذه المقالة التي تصف بشكل واضح كَيفية الوصول للإجراءات المخزونة واستخدامها ، إلا إن الصنف Dbtier المصاحب لها بحاجة لبعض التحسينات كي تصبح منتج ذونوعية عالية فهو يفتقرلكود معالجة الخطأ. وبحاجة أيضاً لأبعد من ذلك المزيد من الجهد لتحسين الأداءِ.
الشفرة المصدرية لهذه المقالة موجودة ضمن الملف DBTier.vb بالإضافة لبعض النماذج البسيطة جداً لإختِبار وتطبيقِ الصنف فعلياً.
الخلاصة : أَتمنى أن تكون قد اكَتسبت أمرين على الأقل من هذه المقالة. أحدهما أن تكون الإجراءاتِ المخزونة ووجودها ضمن Microsoft Access حقيقة قائمة وأنها تعمل بشكل جيد بالرغم من عدم خلوها من بعض القيود. الشيء الثاني أن تكون قد توصلت لَفهم الحاجةَ لتقسيم وتجزيئي تطبيق الوصول للبيانات إلى أصناف مستقلة وإجراءات فرعية ووظائف. فهذا يبسط كثيراً صيانةً وترقية التطبيق.
كامل الشفرة المصدرية للـ DBTier.vb:
Imports System Imports System.Data Imports System.Data.OleDb ' Functions and subroutines for executing Stored Procedures in Access. Public Class DBTier ' Change Data Source to the location of Northwind.mdb on your local ' system. Shared connectionString As String = _ "PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program " _ & "Files\Microsoft Office\Office10\Samples\Northwind.mdb" ' This function returns a dataset containing all records in ' the Products Table. Function ProductsList() As DataSet Dim con As OleDbConnection Dim da As OleDbDataAdapter Dim ds As DataSet Dim sSQL As String sSQL = "EXECUTE procProductsList" con = New OleDbConnection(connectionString) da = New OleDbDataAdapter(sSQL, con) ds = New DataSet() da.Fill(ds, "Products") Return ds End Function ' This Function adds one record to the Products table. Sub ProductsAddItem(ByVal ProductName As String, _ ByVal SupplierID As Integer, ByVal CategoryID As Integer) Dim con As OleDbConnection Dim cmd As OleDbCommand = New OleDbCommand() Dim paramProductName As New OleDbParameter() Dim paramSupplierID As New OleDbParameter() Dim paramCategoryID As New OleDbParameter() con = New OleDbConnection(connectionString) cmd.Connection = con With paramProductName .ParameterName = "inProductName" .OleDbType = OleDbType.VarChar .Size = 40 .Value = ProductName End With cmd.Parameters.Add(paramProductName) With paramSupplierID .ParameterName = "inSupplierID" .OleDbType = OleDbType.Integer .Size = 4 .Value = SupplierID End With cmd.Parameters.Add(paramSupplierID) With paramCategoryID .ParameterName = "inCategoryID" .OleDbType = OleDbType.Integer .Size = 4 .Value = CategoryID End With cmd.Parameters.Add(paramCategoryID) cmd.CommandText = "EXECUTE procProductsAddItem" con.Open() cmd.ExecuteNonQuery() con.Close() End Sub ' This function Updates a specific JobTitle Record with new data. Sub ProductsUpdateItem(ByVal ProductID As Integer, _ ByVal ProductName As String) Dim con As OleDbConnection Dim cmd As OleDbCommand = New OleDbCommand() Dim paramProductName As New OleDbParameter() Dim paramProductID As New OleDbParameter() con = New OleDbConnection(connectionString) cmd.Connection = con With paramProductID .ParameterName = "inProductID" .OleDbType = OleDbType.Integer .Size = 4 .Value = ProductID End With cmd.Parameters.Add(paramProductID) With paramProductName .ParameterName = "inProductName" .OleDbType = OleDbType.VarChar .Size = 40 .Value = ProductName End With cmd.Parameters.Add(paramProductName) cmd.CommandText = "EXECUTE procProductsUpdateItem" con.Open() cmd.ExecuteNonQuery() con.Close() End Sub ' This function deletes one record from the Products table. Sub ProductsDeleteItem(ByVal ProductID As Integer) Dim con As OleDbConnection Dim cmd As OleDbCommand = New OleDbCommand() Dim paramProductID As New OleDbParameter() con = New OleDbConnection(connectionString) cmd.Connection = con With paramProductID .ParameterName = "inProductID" .OleDbType = OleDbType.Integer .Size = 4 .Value = ProductID End With cmd.Parameters.Add(paramProductID) cmd.CommandText = "EXECUTE procProductsDeleteItem" con.Open() cmd.ExecuteNonQuery() con.Close() End Sub End Class
مرفق الملف المثال على ماورد في هذا الجزء من المقالة: