
السلام عليكم ورحمة الله وبركاته
إخواني الكرام أقدم لكم اليوم درس بطريقة إنشاء Microsoft Access (ملف MDB) بالكود أثناء RunTime
باختيار جدول معين وانشاء وتصدير واستيراد الجدول بجميع حقوله وبياناته التي يحتوي عليها .
مقدمة :غالباً ما نحتاج إنشاء قواعد البيانات برمجياً ولكن لا توجد كائنات بيانات (ActiveX (ADO أو ADO.NET لإنشاء قواعد بيانات Microsoft Access بشكل تلقائي .
ولكن يمكن إنشاء قواعد بيانات Microsoft Access عن طريق استخدام Microsoft Jet OLE DB Provider و Microsoft ADO Ext. 2.8 For DLL and Security وكذلك يمكن استخدامها لأي فيرجن موجود لديك من 2.1 إلى 2.8 والأداة هي عبارة ملف msADOX.Dll وهي النسخة القديمة قبل أن تظهر ADO.net وأكيد أنها موجودة عند الجميع لأنها احد مكونات Microsoft Data Access Components 2.8 وموجودة من ضمن Windows XP Service Pack 2 و Windows XP Service Pack 3
مثلا لنفترض انه عندنا ملف mdb ويحتوي على عدة Tables ونأخذ هنا مثال ملف المخازنStore.mdb يحتوي على
جدول product جدول Product_detail جدول Employee جدول Orders وجداول أخرى
ولنفترض أننا نرغب بفصل جدول product فقط بكامل حقوله وتعريفاته والسجلات المخزنة به في ملف MDBمستقل.
الدرس : تم انشاء المشروع على VB.NET 2008 وسيعمل على VB.NET 2005 دون احداث أي تغيير.
انشاء مشروع مفتوح المصدر(أي اننا لن نحدد اسماء الملفات أو الجداول وسنجعلها مفتوحه يمكن ان تعمل على أي ملف MDB) وذلك لانشاء ملف MDB جديد ، تصدير/ استيراد الجداول والحقول والبيانات) وكما في الصورة المرفقة.

افتح مشروع جديد وقم بتصميمه حسب الصورة (وبنفس الاسماء حتى يتطابق مع الكود الذي سأكتبه)
وبعد تصميم الشاشة نضيف الأداة msADOX وذلك بالضغط كلك يمين على Add References ثم نذهب إلى Tab com ونبحث عن و Microsoft ADO Ext. 2.8 For DLL and Security أي فيرجن موجود عندك من 2.1 إلى 2.8
حيث انه يتم إنشاء ملف MDB على انه Microsoft Access 2000 ، ونضيف ايضا الأداة ADODB وهي موجودة بكل تأكيد عند الجميع لانها من ضمن مكتبات vs.net
المشروع :في بداية البرنامج نعمل استيراد للمكتبات التالية
كود
Imports System.IO
Imports System.Data.OleDb
Imports ADOX
ونضيف التعريفات التالية لبداية البرنامج ايضا
كود
Dim path1 As String = ""
Dim path2 As String = ""
Dim TableName As String = ""
Dim tbl As New ADOX.Table
Dim cat1 As New ADOX.Catalog()
Dim cat2 As New ADOX.Catalog()
Dim conn As New ADODB.Connection
Dim ds As New DataSet
Dim idxLoop As New ADOX.Index
Dim colLoop As New ADOX.Column
Dim con1 As OleDbConnection
Dim Con2 As OleDbConnection
Dim dsStore As New DataSet
Dim dsproduct As New DataSet
Dim PrimKey As String = ""
الان نضغط على زر (من ملف) ونكتب التالي لفتح ملف MDB عن طريق استخدام OpenFileDialog1 وتعبئة ListBox1 باسماء الجداول الموجودة به وسنستخدم هنا ADOX في قراءة اسماء الجداول ، وتفريغ Labels و DataGridView1
كود
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Label1.Text = ""
Label2.Text = ""
Label3.Text = ""
Label4.Text = ""
TableName = ""
ListBox1.Items.Clear()
Button1.Enabled = False
Button5.Enabled = False
Me.DataGridView1.DataSource = Nothing
If Me.OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
If OpenFileDialog1.FileName.Length = 0 Then Exit Sub
path1 = OpenFileDialog1.FileName
Label1.Text = path1
Else
Exit Sub
End If
Try
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Persist Security Info=False; Data Source=" & path1
conn.Open()
cat1 = New Catalog
cat1.ActiveConnection = conn
For i As Integer = 0 To cat1.Tables.Count - 1
If cat1.Tables(i).Type = "TABLE" Then ListBox1.Items.Add(cat1.Tables(i).Name)
Next
conn.Close()
cat1.ActiveConnection = Nothing
cat1 = Nothing
Catch ex As Exception
If conn.State = ConnectionState.Open Then
conn.Close()
cat1.ActiveConnection = Nothing
cat1 = Nothing
End If
End Try
End Sub
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
If Me.SaveFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
If Me.SaveFileDialog1.FileName.Length = 0 Then
Label2.Text = ""
Button1.Enabled = False
Exit Sub
Else
path2 = SaveFileDialog1.FileName
Label2.Text = path2
Button1.Enabled = True
End If
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If path1 = path2 Then
MsgBox("لا يمكن انشاء الملف بنفس اسم الفهرس واسم الملف")
Exit Sub
End If
If CreateMDB() Then ' Function لانشاء الملف
Label4.Text = "تم انشاء الملف " & path2
MsgBox("تم انشاء الملف")
Else
MsgBox("حصل خطأ ولم يتم انشاء الملف")
End If
End Sub
بعد ذلك نضغط على زر (الى ملف) ونكتب الكود التالي
كود
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
If Me.SaveFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
If Me.SaveFileDialog1.FileName.Length = 0 Then
Label2.Text = ""
Button1.Enabled = False
Exit Sub
Else
path2 = SaveFileDialog1.FileName
Label2.Text = path2
Button1.Enabled = True
End If
End If
End Sub
الان نضغط على زر (انشاء الملف والجدول والحقول ) وفيه Function لانشاء الملف والجدول والحقول
كود
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If path1 = path2 Then
MsgBox("لا يمكن انشاء الملف بنفس اسم الفهرس واسم الملف")
Exit Sub
End If
If CreateMDB() Then ' Function لانشاء الملف
Label4.Text = "تم انشاء الملف " & path2
MsgBox("تم انشاء الملف")
Else
MsgBox("حصل خطأ ولم يتم انشاء الملف")
End If
End Sub
نقوم الان بكتابة Function لانشاء الملف والجدول والتعريفات ( فقط ) عملة انشاء دون ترحيل للبيانات وهنا سنستخدم اوامر ADOX لخلق الملف وتعريفاته
كود
Function CreateMDB() As Boolean
Try
If File.Exists(path2) Then File.Delete(path2)
conn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Persist Security Info=False; Data Source=" & path1
conn.Open()
cat1 = New Catalog
cat1.ActiveConnection = conn
' Create .mdb
Dim sConnString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & path2
cat2 = New Catalog
cat2.Create(sConnString)
tbl = New ADOX.Table
tbl.Name = TableName
If cat1.Tables(TableName).Type = "TABLE" Then
'هذا الامر لاضافة اسماء الحقول الى الجدول
For Each col As ADOX.Column In cat1.Tables(TableName).Columns
' حجم الحقل نوع الحقل اسم الحقل
tbl.Columns.Append(col.Name, col.Type, col.DefinedSize)
'هذا الامر لتحديد اي الحقول required وذلك لان اذا لم نضعها adox تجعل قيمة جميع الحقول YES
If Not cat1.Tables(TableName).Columns(col.Name).Attributes = ColumnAttributesEnum.adColNullable Then
tbl.Columns(col.Name).Attributes = ColumnAttributesEnum.adColNullable
End If
Next col
' هذا الامر لتحديد واضافة PrimaryKey و Index
For Each Me.idxLoop In cat1.Tables(TableName).Indexes
For Each Me.colLoop In idxLoop.Columns
Next colLoop
If idxLoop.PrimaryKey Then
tbl.Keys.Append(idxLoop.Name, KeyTypeEnum.adKeyPrimary, colLoop.Name)
Else
tbl.Indexes.Append(idxLoop.Name, colLoop.Name)
End If
Next idxLoop
End If
cat2.Tables.Append(tbl)
tbl = Nothing
conn.Close()
cat1.ActiveConnection = Nothing
cat2.ActiveConnection = Nothing
cat1 = Nothing
cat2 = Nothing
Return True
Catch ex As Exception
If conn.State = ConnectionState.Open Then
tbl = Nothing
conn.Close()
cat1.ActiveConnection = Nothing
cat2.ActiveConnection = Nothing
cat1 = Nothing
cat2 = Nothing
End If
Return False
End Try
End Function
بذلك نكون قد تم إنشاء الملف MDB يحتوي على الجدول الذي قمنا باختيارة من ListBox1 بجميع حقوله وتعريفاته وكما في الملف الأصلي ويخزن على أساس Microsoft Access 2000
وبعد ذلك نقوم بالضغط على زر (تصدير البيانات) ونكتب الكود التالي وهنا سأقوم باستخدام ADO.net بما أنني قد حصلت على ملف mdb جاهز لإضافة البيانات إليه.
كود
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
If path1 = String.Empty Or path2 = String.Empty Or TableName = String.Empty Then
MsgBox("يجب تحديد اسماء الملفات والجدول")
Exit Sub
End If
Dim i As Integer = 0
Label5.Text = ""
Label6.Text = ""
Try
'وتعبئة البيانات الاصلي نقوم هنا بالاتصال بالملف
Dim StrCon As String = "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;data source=" & path1
con1 = New OleDbConnection(StrCon)
Dim Cmd1 As String = "SELECT * from " & TableName
con1.Open()
Dim dr As OleDbDataAdapter = New OleDbDataAdapter(Cmd1, con1)
dsStore.Clear()
dr.Fill(dsStore, TableName)
Me.DataGridView1.DataSource = dsStore.Tables(TableName)
Label5.Text = dsStore.Tables(TableName).DefaultView.Count
DataGridView1.Refresh()
'الذي قمنا بانشاؤه وتعبئة البيانات نقوم هنا بالاتصال بالملف
Dim ProCon As String = "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;data source=" & path2
Con2 = New OleDbConnection(ProCon)
Dim Cmd2 As String = "SELECT * from " & TableName
Con2.Open()
Dim drpro As OleDbDataAdapter = New OleDbDataAdapter(Cmd2, Con2)
drpro.MissingSchemaAction = MissingSchemaAction.Add
drpro.Fill(dsproduct, TableName)
Me.ProgressBar1.Value = 0
Me.ProgressBar1.Maximum = dsStore.Tables(TableName).Rows.Count + 100
'نقوم هنا بانشاء اوامر الاضافة والتعديل والالغاء
Dim Comb As OleDbCommandBuilder = New OleDbCommandBuilder(drpro)
' MsgBox(Comb.GetInsertCommand.CommandText.ToString)
ونكمل الان وسنبدأ بقرائة البيانات وهنا استخدمت اسم الحقل وليس index للحقل وذلك لانه عندما انشأنا الحقول عن طريق ADOX يقوم بترتيب الحقول ابجديا وليس كما هي مرتبه في الملف الاصلي .
لذلك يجب استخدام اسم الحقل والا سيعطي خطا Type Mismatch كود
Dim prNewRow As DataRow
While i < dsStore.Tables(TableName).Rows.Count
prNewRow = dsproduct.Tables(TableName).NewRow()
For j As Integer = 0 To dsStore.Tables(TableName).Columns.Count - 1
prNewRow.Item(dsproduct.Tables(TableName).Columns.Item(j).ColumnName) = _
dsStore.Tables(TableName).Rows(i).Item(dsproduct.Tables(TableName).Columns.Item(j).ColumnName)
Next
dsproduct.Tables(TableName).Rows.Add(prNewRow)
drpro.Update(dsproduct, TableName)
i += 1
Me.ProgressBar1.Value = i
End While
drpro.Update(dsproduct, TableName)
dsproduct.AcceptChanges()
Me.ProgressBar1.Value = Me.ProgressBar1.Maximum
Label6.Text = dsproduct.Tables(TableName).DefaultView.Count
Me.DataGridView2.DataSource = dsproduct.Tables(TableName)
con1.Close()
Con2.Close()
Catch ex As Exception
If con1.State = ConnectionState.Open Then
con1.Close()
End If
If Con2.State = ConnectionState.Open Then
Con2.Close()
End If
Me.ProgressBar1.Value = Me.ProgressBar1.Maximum
MessageBox.Show(ex.Message)
Finally
MessageBox.Show(" لقد تمت عملية تصدير (" & i & ") سجل ", "تمت العملية", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
Me.ProgressBar1.Value = 0
End Try
End Sub
وهنا نكون قد انتهينا وأصبح عندنا ملف mdb مخزن فيه الجدول الذي قمنا باختياره وجميع الحقول والبيانات ومتطابق تماما مع الجدول في الملف الأصلي .
بعد ذلك نضغط على زر (استيراد البيانات) لنفترض أننا نرغب في استيراد الملف mdb الذي قمنا بانشاؤه وتصدير البيانات له وتخزين محتوياته في الملف الأصلي . وهنا يوجد عندنا حالتين (اضافة و تعديل) وذلك بافتراض اننا قمنا باجراء تغيير على الملف
MDB الذي قمنا بانشاؤه سواء بإضافة مواد جديدة عليه أو تعديل السجلات الموجودة فيه وأننا نرغب باستيراد الملف وتخزينه في الملف الأصلي أي (يجب مراعاة أن السجل غير موجود في الأصلي فلذلك يجب إضافته والحالة الأخرى أن السجل موجود فيجب تعديله).
لذا نضغط على الزر استيراد ونكتب الحدث التالي:
اولا : نقوم بعمل اجراء لمعرفة ما هو اسم حقل PrimaryKey وذلك عن طريق ADOX وهو مهم جدأ حيث اننا سوف نقوم بترتيب السجلات في كلا الملفين حسب PrimaryKey
كود
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim dsImp As New DataSet
Dim i As Integer = 0
If path1 = String.Empty Or path2 = String.Empty Or TableName = String.Empty Then
MsgBox("يجب تحديد اسماء الملفات والجدول")
Exit Sub
End If
Label6.Text = ""
Try
Dim conn As New ADODB.Connection
conn.ConnectionString = _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Persist Security Info=False;" & _
"Data Source=" & path1 & ";Jet OLEDB:Engine Type=5"
conn.Open()
Dim cat1 As New ADOX.Catalog
cat1.ActiveConnection = conn
For j As Integer = 0 To cat1.Tables.Count - 1
If cat1.Tables(j).Type = "TABLE" Then
For Each Me.idxLoop In cat1.Tables(TableName).Indexes
For Each Me.colLoop In idxLoop.Columns
Next colLoop
If idxLoop.PrimaryKey Then
PrimKey = colLoop.Name
End If
Next idxLoop
End If
Next
cat1.ActiveConnection = Nothing
conn.Close()
cat1 = Nothing
بعد ذلك نقوم بقراءة الملفين في dataset عن طريق ADO.net ، وبناء أوامر التعديل والإضافة والإلغاء في DataAdapter عن طريق OleDbCommandBuilder وبشكل تلقائي، وتعريف datarow للأصلي والمستورد .
كود
Dim StrCon As String = "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;data source=" & path2
con1 = New OleDbConnection(StrCon)
Dim Cmd1 As String = "SELECT * from " & TableName & " ORDER BY " & PrimKey
con1.Open()
Dim dr As OleDbDataAdapter = New OleDbDataAdapter(Cmd1, con1)
ds.Clear()
dr.Fill(ds, TableName)
Me.DataGridView1.DataSource = ds.Tables(TableName)
Label5.Text = ds.Tables(TableName).DefaultView.Count
Label5.Refresh()
DataGridView1.Refresh()
Dim StrImp As String = "Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;data source=" & path1
Con2 = New OleDbConnection(StrImp)
Dim Cmd2 As String = "SELECT * from " & TableName & " ORDER BY " & PrimKey
Con2.Open()
Dim DrImp As OleDbDataAdapter = New OleDbDataAdapter(Cmd2, Con2)
DrImp.MissingSchemaAction = MissingSchemaAction.Add
DrImp.Fill(dsImp, TableName)
Dim DrComm As OleDbCommandBuilder = New OleDbCommandBuilder(dr)
Dim ImpRow As DataRow
Dim OrgRow As DataRow
بعد ذلك نقوم بعمل CurrencyManager للملف الاصلي وعمل sort له لنستطيع تحديد موقع السجل المراد تعديله عن طريق البحث عنه فإذا موجود نعدله واذا غير موجود نضيفه.
واكرر هنا الشرط أننا نعدل حسب اسم الحقل وليس حسب index له لأنهما مختلفان في الترتيب.
كود
Dim ThisRow As Integer = 0
Dim Rowpostion As CurrencyManager = CType(BindingContext(ds, TableName), CurrencyManager)
ds.Tables(TableName).DefaultView.Sort = PrimKey
Try
Me.ProgressBar1.Value = 0
Me.ProgressBar1.Maximum = Rowpostion.Count + 100
While i < dsImp.Tables(TableName).Rows.Count
ImpRow = dsImp.Tables(TableName).Rows(i)
ThisRow = ds.Tables(TableName).DefaultView.Find(ImpRow.Item(PrimKey))
If ThisRow < 0 Or ThisRow > ds.Tables(TableName).Rows.Count Then
'السجل غير موجود ويجب اضافته
OrgRow = ds.Tables(TableName).NewRow()
For j As Integer = 0 To ds.Tables(TableName).Columns.Count - 1
OrgRow.Item(ds.Tables(TableName).Columns.Item(j).ColumnName) = _
ImpRow.Item(ds.Tables(TableName).Columns.Item(j).ColumnName)
Next
ds.Tables(TableName).Rows.Add(OrgRow)
Else
'السجل موجود ونقوم بتعديله
Rowpostion.Position = ThisRow 'لتحديد ترتيب السجل
OrgRow = ds.Tables(TableName).Rows(ThisRow)
For j As Integer = 0 To ds.Tables(TableName).Columns.Count - 1
OrgRow.Item(ds.Tables(TableName).Columns.Item(j).ColumnName) = _
ImpRow.Item(ds.Tables(TableName).Columns.Item(j).ColumnName)
Next
End If
i += 1
Me.ProgressBar1.Value = i
End While
Catch ex As Exception
Me.ProgressBar1.Value = Me.ProgressBar1.Maximum
MessageBox.Show(Err.Number & ex.Message)
End Try
'لمعرفة السجلات التي اضيفة أو عدلت
Dim ss As DataTable = ds.Tables(TableName).GetChanges(DataRowState.Modified Or DataRowState.Added)
dr.Update(ds, TableName)
ds.AcceptChanges()
Me.ProgressBar1.Value = Me.ProgressBar1.Maximum
Label6.Text = ss.DefaultView.Count
Me.DataGridView2.DataSource = ss 'للتأكد من السجلات المعدلة أو المضافة
con1.Close()
Con2.Close()
Catch ex As Exception
If con1.State = ConnectionState.Open Then
con1.Close()
End If
If Con2.State = ConnectionState.Open Then
Con2.Close()
End If
MessageBox.Show(ex.Message)
Finally
MessageBox.Show(" لقد تمت عملية الاستيراد (" & i & ") سجل ", "تمت العملية", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
Me.ProgressBar1.Value = 0
End Try
End Sub
وهكذا نكون قد انتهينا من استيراد الملف الذي قمنا بتصديرة .
والان نقوم بالضغط على Listbox1 مرتين ونكتب الاجراء التالي وهو لتحديد اسم الجدول الذي نرغب في انشاؤه أو تصديره او استيرادة
كود
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Me.TableName = ListBox1.Text
If Me.TableName <> "" Then
Label3.Text = Me.TableName
Button5.Enabled = True
Else
Button5.Enabled = False
End If
End Sub
ويمكن استخدام امر الاستيراد دون انشاء الملف وتصديره
(بشرط ان يكون الجدول المراد استيرادة متطابق تماما مع الملف الاصلي)وبهذا نكون قد انتهينا من المشروع مع تمنياتي لكم بالتوفيق.