اذهب الي المحتوي
أوفيسنا

الردود الموصى بها

قام بنشر (معدل)

السلام عليكم

إخواني وأخواتي ، بارك الله فيكم جميعاً

الدرس الأول : الحقات التكرارية (الدورانية) : Looping

في كثير من الأحيان يحتاج المبرمج إلى تكرار تنفيذ مجموعة من التعليمات عدداً من المرات، ويوجد طرقتين أساسيتين للتكرار في حالة كان عدد مرات التكرار معروفة مسبقا حيث يجب استخدام For ... Next ، وإذا كان عدد مرات التكرار غير محددة مسبقاً ومبنية على تحقق شرط معين (شرط إنتهاء الدوران أو البقاء به) فهنا نستخدم Do ... Loop .

يوجد أربع أشكال لحقات الدوراان التكرارية المبنية على شرط وبجميعها يكون هناك شرط يحدد استمرار التكرار أو توقفه. وقيمة الشرط ستكون إما True أو False ، أو تعبير يرُُجع قيمة رقمية حيث تعتبر القيمة التي لا تساوي صفراً True وإلا False.

أشكال البنى التكرارية الأربعة :

1. تنفيذ التعليمات statments هنا سيستمر حتى يتحقق الشرط condition .

Do Until condition
 Statments
Loop
وعندما يصل أكسيس لتفيذ هذا الدوران ، فإنه سيبدأ وقبل كل شيء بفحص قيمة الشرط conditon، فإذا كان True ، سيتم الإنتقال فوراً إلى ما بعد التكرار أي أنه لن يتم الدخول للحلقة. أما إذا كان False ، فسيتم تنفيذ التعليمات satments ،ثم يرجع للسطر DO Until ، للقيام بفحص الشرط ثانية، وهكذا ... إذاً ، سيتم تكرار الحلقة عدداً من المرات ، طالما بقي الشرط conditon قيمته False . ولن ينفذ ولو مرة واحدة إذا كان الشرط True. ويجب في الحقات التكرارية المبني إنتهائها على شرط أن نلاحظ أنها لن تنتهي ما لم يتحقق الشرط ويجب العمل على تحقيقه في داخل الحلقة في لحظة ما وإلا سيستمر الدوران إلى ما لا نهاية ويعلق الجهاز. ولنأخذ مثالاً حتى نفهم كيف سيتم التعامل مع هذا الشكل من أشكال الحلقات الدورانية: نريد أن نجمع مجموعة من الأرقام المدخلة إلى الحاسوب ونطبع نتيجة جمعها . عندما ندخل العدد 999 نتوقف عن الإدخال.
sum = 0
x= InputBox("أدخل الرقم ")
do until x=999
sum = sum+x
x= InputBox("أدخل الرقم ")
loop
Msgbox sum
مع ملاحظة ما يلي : 1. أننا قمنا أولا بتحديد قيمة المجموع وهي بالبداية صفراً 2. ثم قمنا بإدخال القيمة الإبتدائية قبل الدخول للحلقة وهي X ويتم إدخالها من قبل المستخدم عند تشغيل البرنامج. 3. بناء على قيمة x فإذا كانت 999 يكون الشرط true ولا ندخل للحلقة وإلا يكون false وندخل في داخل الحلقة نقوم بزيادة قيمة sum االمجموع بمقدار القيمة المدخلة وهي x . 4. ثم تأتي عملية الإدخال من جديد داخل الحلقة والتي بدونها لن ينتهي التكرار حيث من خلال هذه الجملة سيتم وقف التكرار وذلك عند إدخال القيمة 999. 5. وفي نهاية البرنامج نطبع القيمة المطوبة وهي مجموع الأرقام التي تم إدخالها. 2. الشكل الثاني من أشكال الحلقات سيقوم بتنفيذ الدوران على الأقل مرة واحدة حيث يتم الدخول للحلقة أولا ثم في نهاية الحلقة يتم فحص الشرط :
Do
Statements
Loop Until condition
عندما يصل أكسيس لهذه الحلقة يتم الدخول فيها فورا وتنفيذ الجمل statements وبعد تنفيذها يتم فحص الشرط condtion فإذا كان true يخرج من الدوران وإلا يبقى وينفذ مرة أخرى وهكذا ... ولنأخذ المثال التالي : نريد أن نحسب مساحة مجموعة من الدوائؤ وعندما ندخل أن نصف القطر للدائرة صفراً تتوقف الحقلة (الدوران).
Private Sub ex2_Click()
Do
r = InputBox("أدخل نصف القطر")
a = r ^ 2 * 22 / 7
MsgBox "المساحة= " & a
Loop Until r=0
End Sub
وأرجو ملاحظة ما يلي : 1. تم الدخول للحلقة مباشرة دون شرط أو قيد ولهذا سيتم تنفيذ الحلقة على الأقل مرة واحدة 2. تم إدخال نصف القطر r حيث سليزم لحساب مساحة الدائرة والتي تساوي مربع نصف القطر مضروبا في النسبة التقريبية ط والتي تساوي 22/7. 3. يتم احتساب مساحة الدائة وطباعة النتيجة وذلك داخل الحلقة ايضاً. 4. في نهاية الحقلة يتم السؤال عن الشرط فإذا كانت قيمة نصف القطر r=0 فسنخرج من الحلقة والا ننتقل لإدخال نصف قطر جديد وحساب مساحة جديد وهكذا .. 3. في الشكل الثالث من أشكال الدوران ، تنفذ التعليمات طالما أن قيمة الشرط condition صحيحة true وإلا يتم التوقف عن الدوران في الحلقة التكراارية.
do while condition
statements
loop
عندما يصل الأكسيس إلى هذه الحلقة يفحص قيمة الشرط أولا وقبل الدخل للدوران فإذا كان صحيحاً يستمر في الدوران وإلا يخرج من الدوران. ولنأخذ المثال التالي : نريد أن نقرأ مجموعة من الأسماء ونطبعها وإذا كان الحرف الأول في الكلمة ع (حرف العين) نتوقف.
Private Sub ex3_Click()
na = InputBox("أدخل أسم")
Do While Left(na, 1) <> "ع"
 MsgBox na
 na = InputBox("أدخل أسم")
Loop
End Sub
ومن المهم ملاحظة ما يلي : 1. يتم إدخال اسم ابتدائي قبل الدخول للحلقة حيث سيتم فحص الشرط مباشرة 2. لاحظ أن الشرط هو بالسؤال عن الحرف الأول من اليسار Left للاسم وإذا لم يكن يساوي حرف العين نستمر في الدوران وعندما ندخل اسم يكون أول حرف فيه عين يتم التوقف والخروج من الدوران. 3. في داخل الدوران سيتم طباعة النتيجة المطلوبة وهي الأسم ثم سيتم السؤال عن الأسم التالي تمهيدا لتنفيذ الدورة الثانية وهكذا ... 4. الشكر الرابع والأخير من أشكال الحلقات الدورانية المشروطة يتم فيه تنفيذ التعليمات مرة واحدة على الأقل وهو كما يلي :
Do
statements
Loop While condition
وهنا عندما يثل الأكسيس إلى الحلقة يتم الدخول مباشرة لها وتنفيذ الجمل التي بها statements ثم يتم الؤال عن صحة الشرط condtion حيث إذا كان true يستمر في الدوران وإلا يتم الخروج منه. ولنأخذ المثال التالي وهو حساب مجموع مربعات (تربيع) الأعداد المدخلة . نتوقف عن الحساب ونطبع النتيجة المجموع عندما ندخل العدد 0.
Private Sub ex5_Click()
sum = 0
Do
x = InputBox("أدخل رقم")
sum = sum + x ^ 2
Loop While Not x = 0
MsgBox "مجموع مربعات الأعداد المدخلة هو " & sum
End Sub
لاحظ أن شرط الإنتهاء هو not x = 0 وهو مكافىء للشرط x<> 0 حيث الرمز <> يعني لا يساوي. لاحظ أيضا أنه في جميع الأشكال الأربعة الساقة لم يحدد في الأمثلة عدد مرات التنفيذ وهكذا تستخدم الحلقات الدورانية في هذه الأشكال عندما لا يعرف عدد مرات التنفيذ (الدوران) مسبقاً. أما إذا كنا نعلم عدد مرات التنفيذ (الدوران) فإنه من غير المفضل نهائياً استخدام الأشكال السابقة ويجب استخدام الشكل الخاص بالتكرار المروف مرات الدوران مسبقا وهو For .. do التالي :
For counter = start to end [Step increment]
statments
Next [Counter]
حيث أن : counter : متغير (عداد الحلقة التكرارية) start : القيمة الإبتدائية للدوران end : القيمة النهائية للدوران increment : مقدار الزيادة في كل مرة من مرات الدوران وإذا لم يوضع تكون الزيادة بشكل معياري هي 1 ويمكن أن يكون increment موجب أو سالب فإذا كان سالب يجب أن تكون القيمة النهائية أضغر من الإبتدائية. وإليكم كيفية تعامل أكسيس مع هذا النوع من الحلقات : 1. عند الدخول للدوران for يتم وضع قيمة counter تساوي القيمة الإبتدائية start . 2. يتم ومباشرة وقبل تنفيذ الجمل التي تلو for إذا كانت قيمة العداد counter أكبر من القيمة النهائية end فإن كانت كذلك يتم إنهاء الدوران والخروج منه . أما إذا كانت قيمة Increment سالبة فإن الفحص يتم بطريقة عكسية حيث يتم التأكد فيما إذا كانت قيمة العداد counter أقل من القيمة الإبتدائية start وإذا كانت كذلك يتم الخروج من الحلقة. 3. يتم تنفيذ الجمل التي في الحلقة 4. يتم زيادة قيمة العداد بمقدا واحد أو increment إذا كان محدداً. 5. وهكذا يتم تكرار الخطوات من 2 إلى 4 في كل مرة. ولنأخذ المثال التالي نفرض أننا نريد جمع الأعداد الزوجية من 1 - 100 وطباعة النتيجة :
Private Sub ex6_Click()
sum = 0
For i = 1 To 100 Step 2
sum = sum + i
Next i
MsgBox "المجموع هو " & sum
End Sub
وفي مثالنا الثاني نريد أن نقرأ سام نموذج فإذا كان مفتوح نطبع أن النموذج مفتوح وإلا نطبع غير مفتوح
Private Sub ex7_Click()
n = InputBox("أدخل اسم النموذج")
IsOpen = False
For i = 0 To Forms.Count - 1
 If Forms(i).FormName = n Then
  IsOpen = True
 End If
Next i
If IsOpen Then
 MsgBox " النموذج مفتوح"
Else
 MsgBox "النموذج غير مفتوح"
End If
End Sub

لاحظ أن للنماذج المفتوحة رقم يبدأ من صفر forms.count

ولاحظ اسم النموذج forms(I). formname

أما باقي الأمور في الحلقة فأعتقد أنه سهلة.

مع الاحترام والتقدير

=الدروس=

looping.rar

تم تعديل بواسطه خضر الرجبي
  • Like 1
  • Thanks 2
قام بنشر

السلام عليكم

إخواني ، بارك الله فيكم وشكراً على تثبيت الموضوع

ملحق الدرس الأول :

بالنسبة للحلقات المشروطة لا يوجد طرق أخرى .

وقاعدة كتابة هذه الجمل بشكلها المتكامل هو كما يلي :

Syntax

Do [{While | Until} condition]
[statements]
[Exit Do]
[statements]

Loop

Or, you can use this syntax:

Do
[statements]
[Exit Do]
[statements]

Loop [{While | Until} condition]
بالنسبة للحلقات غير المشروطة على غرار for ... next يوجد أيضا تركيب أخر مهم لا نستطيع تجاهله وهو for each ... next وكمثال عليه أقدم لكم ما يلي : هذا الموضوع يتماشى مع Access 2002 و Access 2003 يستفاد من هذا الموضوع معرفة طريقة إضافة الطابعات المحملة (المعرفة) لجهاز الحاسوب إلى مربع تحرير وسرد (combo box) باستخدام البرمجة بلغة(VBA) . خطوات الطريقة هي : 1. ندخل إلى خصائص مربع التحرير والسرد ونضغط لسان التبويب الكل (All tab). 2. نغير قيم الخصائص كما يلي : نضع في خاصية الاسم (Name) الاسم dPrinter نختار في خاصية نوع مصدر الصف (Row Source Type) قائمة الحقول (Value List) نضع في حدث عند التحميل للنموذج (On Load) الكود التالي:
Private Sub Form_Load()
Dim prt As Printer
For Each prt In Application.Printers
Me!dPrinter.AddItem prt.DeviceName
Next
End Sub

ملاحظة(1): عندما نضيف (نحمل) عناصر لمربع التحرير والسرد بالبرمجة (كما في المثال السابق) فإن العناصر لا تترتب أبجديا وإنما حسب ترتيب التحميل طبعا هناك حل لهذا الأمر أيضا، أرجو من الإخوة الأعضاء التفكير في الحل.

ملاحظة(2): انتبه إلى طريقة استخدام (AddItem).

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

مع الاحترام والتقدير

  • Like 1
  • Thanks 1
قام بنشر

السلام عليكم

إخواني وأخواتي :fff: ، بارك الله فيكم جميعا

الملحق 2 : نهاية درس الحلقات التكرارية .

1. يجدر الإشارة إلى تركيب أخر دوراني يندر استعماله حيث أن كفاءة الدورانات السابقة أكثر منه ولأنه لا يحتوي على طريقة للخروج إلا بتحقق شرطه وهو التركيب التالي :

While condition
[statements]
Wend
ويعمل طالما تحقق الشرط condition وبقي محققا يعني true فسيستمر تنفيذ التعليمات statements وعندما يصبح الشرط false يتنهي الدوران ولنأخذ مثالا عليه : لو أردنا أن نقوم بقراءة مجموعة كلمات وطباعة هذه الكلمات في النهاية على شكل جملة بحيث تنتهي القراءة عند إدخال كلمة توقف فيكون المثال كما يلي :
Private Sub PrintStatement_Click()
Dim W, Stat As String
Stat = ""
W = ""
While Not W = "توقف"
 W = InputBox("أدخل كلمة")
 Stat = Stat & " " & W
Wend
MsgBox Left(Stat, Len(Stat) - 4)
End Sub
لاحظوا أننا طبعنا في النهاية قيمة state المتغير النصي الذي سيحتوي على كل الكلمات ولكن - 4 أي بدون الأربعة الحروف الأخيرة لأنها ستكون الكلمة توقف . 2. الخروج من الحلقات الدورانية: بشكل عام وكما لاحظنا في الدرس الأول فإن الخروج من الحلقة المشروطة يتم عندما يتحقق الشرط المطلوب للخروج وكذلك الحال بالنسبة للحلقات غير المشروطة for ... next فإن الخروج يتم عند اتمام عدد المرات للدوران. يمكن في كل الأحول ما عدا في (while ... wend) استخدام الخروج المباشر exit for أو exit do ومن أي مكان داخل الحلقة ، ويتم الخروج إلى الجملة التي تلي الحلقة مباشرة. فمثلا في مثال تحديد فيما إذا كان نموذج ما (معروف اسمه) مفتوحا أو لا سيترتب علينا عمل دورة ندور بها في كل النماذج ونفحص بها إذا كان النموذج مفتوحا أو لا ، والسؤال المفيد الذي يطرح نفسه هنا لماذ نستمر في الدوران إذا وجدنا النموذج المطلوب مفتوحاً، بكل تأكيد أن الجواب هو لا داعي للإستمرار في الدوران لأن ذلك سيكون مضيعة للوقت ، ويجب الخروج الفوري من الدوران . وللنظر إلى الإقتران التالي :
Function IsOpen(ByVal MyFormName As String) As Boolean
Dim i
IsOpen = False
For i = 0 To Forms.Count - 1
 If Forms(i).FormName = MyFormName Then
  IsOpen = True
  Exit For
 End If
Next i
End Function
وطريقة طلب الإقتران ستكون كما يلي :
Private Sub FormCmd_Click()
 MsgBox IsOpen("form1")
End Sub
لاحظ أيضا أن هذا المثال يبين أنه يمكن استخدام exit من داخل if ، وكذلك يمكن استعمالها داخل جملة select إذا كان داخل دوران. 3. التكرار (الدوران) المتداخل Nested Loops مما لا شك فيه أن الدوران يمكن أن يتداخل ولنأخذ مثال على ذلك : نريد أن نقرأ من المستخدم كلمة فإذا كانت واحد يطلب منا إدخال رقم وإذا كانت أثنين يطلب منا إدخال رقمين وهكذا حتى خمسة وإذا طبعنا أي شيء غير واحد إلى خمسة يتوقف العمل وفي النهاية يطبع لنا مجموع جميع الأرقام التي تم إدخالها
Private Sub AddAll_Click()
Dim w As String
Dim out As Boolean
sum = 0
Do
 w = InputBox("الرجاء إدخال عدد الأرقم التي تريد جمعها واحد إلى خمسة أو اي شيء اخر للخروج")
 Select Case w
  Case "واحد": last = 1
  Case "اثنين": last = 2
  Case "ثلاثة": last = 3
  Case "اربعة": last = 4
  Case "خمسة":: last = 5
  Case Else: last = 0
             out = True
  End Select
  For i = 1 To last
   sum = sum + InputBox("أدخل رقم")
  Next i
Loop Until out
MsgBox "المجموع هو " & sum
End Sub

لاحظوا أنه في case else

1> تم تعيين قيمة out = true وذلك للخروج من الحلقة الخارجية المسؤولة عن إدخال الكلمات حيث ان هذه الحالة case يتم الدخول إليها في حال أدخلنا كلمة غير من واحد إلى خمسة.

2> تم تعيين قيمة last =0 حتى لا يتم تنفيذ الدوران for .. next لأنه يبدأ من 1.

أترككم الآن مع هذا الدرس وسأذهب لأعد لكم درس جديد سيكون عن مجموعة التسجيلات فانتظروني ... :d

مع الاحترام والتقدير

ex1_re2.rar

  • Like 1
  • Thanks 1
قام بنشر (معدل)

السلام عليكم

إخواني وأخواتي ، بارك الله فيكم جميعاً

أرحب بكم بهذا الدرس "التعامل مع مجموعات التسجيلات" أملا أن يكون فيه الفائدة لكم.

قبل أن نخوض في تفاصيل وطرق التعامل مع مجموعة التسجيلات يجب أن نعرف ما هو المقصود بمجموعة التسجيلات والتي يسميها البعض أيضا بمجموعة السجلات ، والتي هي عبارة عن مجموعة السجلات محور الإهتمام في نموذج أو تقرير أو عنصر تحكم في مربع نص أو عنصر تحكم مربع تحرير وسرد أو متغير في وحدة نمطية ، (والحقيقة لا أجد لها أماكن استخدام غير الخمسة المذكورة) وهذه السجلات في شكلها البسيط ممكن أن تكون جدول واحد مؤلف من عدة حقول ، وممكن أن تكون مبنية من عدة جداول وبناء على شروط قد تكون معقدة، وتعتبر جميع نتائج الاستعلامات أو تعليمات SQL مجموعات تسجيلات.

مجموعة التسجيلات Recordset هي كائن ، يعتبر من أكثر وأهم الكائنات استعمالا في VBA، ولذا أعزائي الأعضاء ، أحببت أن يكون شرحه في مقدمة دروسنا في VBA.

ودرسنا اليوم تحديداً عن الكائن Recordset في DAO : Data Access Object.

يوجد في هذا الكائن المهم أكثر من 30 خاصية و 18طريقة (أمر) وتقريباً كل قوة محرك بيانات أكسيس Jet ، في عمليات الإضافة والحذف والتعديل والبحث والفرز والتصفية على البيانات تكمن في الكائن Recordset.

وقبل البدء بشرح كيفية التعامل مع مجموعة التسجيلات أرجو منكم أن تحفظوا الجملة التالية التي لن نفهمها تماماً إلا بعد اتمام الدرس كاملا والذي هو طويل نوعاً ما وتجدر الإشارة إلى هذه الجملة المهمة الأن وقبل البداية :

" إن سلوك القراءة والكتابة في مجموعة التسجيلات يعتمد على نوع الكائن (ADO أو DAO) ويعتمد كذلك على نوع البيانات (Jet أو ِSQL) المعرفة بواسطة الكائن Recordset"

وسأراجع معكم هذه الجملة في أخر الدرس التي بإذن الله عندها ستكون من الخبراء في استعمال مجموعات التسجيلات .

وبكل تأكيد أن التعامل مع مجموعة التسجيلات بتقنية ADO هي الأحدث ولن نغفل ذلك نهائيا وسأحاول (حيثما أمكن ) وضع الأمثلة بطريقة ADO وكذلك DAO وما هذه إلا البداية والله الموفق ، علما أنني بذلك أحاول ربط القديم بالجديد وفي ذلك فوائد عديدة منها إلقاء الضوء على الطريقتين وتشجيع البعض ممن لم يتعامل مع أحدى التقنيات أن يستعملها أو على الأقل يستفيد منها في فهم الأمثلة التي تملىء المنتديات والتي فيها مزيجا من هذه التقنيات ولا أخفيكم أن هذه الفكرة قد تبادرت إلى ذهني بعد التفكير ملياً بأحسن الوسائل لطرح الموضوع بما فيه مصلحة الأعضاء العامة وبتشجيع من إخواني الخبراء في جامعة أهلا عرب وبعد استشارة أخي أبا هادي من أوفيسنا جزاهم الله خيراً.

يوجد أربعة أنواع من مجموعات التسجيلات في DAO

1. النوع Table: ويستخدم لتحديد جدول في قاعدة البيانات الحالية فقط ، ولا يمكن استخدامه لتحديد استعلام أو جدول مرتبط من قاعدة أخرى ، ويمكن أن يستخدم هذا النوع للإضافة، الحذف ، التعديل ، أو البحث في الجدول، وعندما نستخدم هذا النوع فإن التغيرات والتعامل تكون مع الجدول مباشرة ، ومن مميزاته الحسنة أنه يسمح باستخدام أسرع طريقة للبحث عن التسجلات بالأمر seek الذي يبحث في الفهارس المعرفة على الجدول.

إخواني وأخواتي ، لا أريد أن أطيل عليكم بالتفاصيل النظرية عن جميع الأنواع والنظريات المتعلقة بالموضوع لأنه طويل جدا وستملون الموضوع بك تأكيد ، لذا سأنتقل مباشرة إلى التطيبق العملي حتى نفهم ما توصلنا إليه حتى الأن ونستوعبه ونطبقه عملياً .

تجدون في المرفق قاعدة بيانات فيها 3 جداول فقط ا الموظفين (employees) والأقسام (departments) والوظائف (jobs) بحيث أن لكل قسم مسؤولا (موظفاً) واحدا فقط ولكل موظف مسئول مباشر عنه وكل موظف يتبع لقسم ما ولكل موظف وظيفة محددة.

إذا كنت لا تعرفون الكثير عن الجداول والعلاقات وطريقة التحليل والتصميم للوصول إلى النتيجة التالية كما في الصورة فيجب مراجعة الموضوع التالي وفهمه جيداً هنا الموضوع :

krajabi1.jpg

أرجو منكم تفحص تصميم الجداول وخصائص الحقول جيداً.

ما سبق هو ليس موضوعنا الأساسي ... الآن ننتقل إلى الموضوع :

في مثالنا الأول نريد أن نبحث عن رقم موظف وإذا كان موجودا في جدول الموظفين نطبع اسم الموظف وعائلته وإذا لم يكن موجودا نطبع أن الرقم المدخل غير موجود ، ومن هنا نبدأ فهمنا لمجموعة التسجيلات ...

Private Sub example1_Click()

Dim MyDb As Database
Dim rstEmployees As Recordset

Set MyDb = CurrentDb
Set rstEmployees = MyDb.OpenRecordset("employees")

id = InputBox("أدخل رقم الموظف")

rstEmployees.Index = "PrimaryKey"
rstEmployees.Seek "=", id
If rstEmployees.NoMatch Then
 MsgBox "هذا الرقم غير موجود"
Else
 MsgBox rstEmployees!EmpFirst & " " & rstEmployees!empfamily
End If

rstEmployees.Close

End Sub
وإليكم الملاحظات المهمة التالية : 1. بناء المتغير من نوع recrodset هو عن طريق OpenRecordset ويوجد لها شكلان واحد لبناء مجموعة التسجيلات من قاعدة البيانات كما في مثالنا والثاني لبناء مجموعة التسجيلات من TableDef أو QueryDef أو من Recordset وأعدكم أنني لن أتشعب كثيرا حيث الموضوع طويل وسأركز حديث في الغالب حول الأمثلة التي أطرحها ، وبإمكانكم بعد فهم الأساسيات التوسع بالموضوع بكل سهولة. الشكل العام لطريقة بناء المتغير والتي استعملناها في مثالنا هي :
set rst = database.openrecordset(source,type,options,lockedits)

حيث

1- rst اسم المتغير من النوع recrodset

2- database اسم المتغير من نوع database

3- source متغير نصي ، اسم جدول أو استعلام او أمر sql ترجع سجلات. أما في مثالنا حيث النوع هو table ، فيجب أن يكون source اسم جدول

4- type وهو ثابت رقمي يحدد نوع المجموعة من (dbopentable،dbopendynaset، dpopensnapshot، dbopenforwardonly) ويوجد نوع خامس يستخدم فقط مع ODBCDIRECT وهو dbopendynamic

مع ملاحظة أنه إذا فتحنا مجموعة سجلات بدون أن نحدد نوعها كما في مثالناً فإن المحرك Jet سينشىء المجموعة بشكل تلقائي من النوع table ، إذا كان المصدر جدولا ، أما إذا كان المصدر استعلاما أو جدولا مرتبطا فإن النوع سيصبح dynaset.

5- options هي مجموعة من الثوابت الإختيارية التي تحدد خصائص مجموعة التسجيلات في بيئة تعدد المستخدمين.

6- lockedits أيضا ثابت اختياري يحدد قفل التسجيلات أو لا.

2. تحديد الفهرس تمهيدا لإستخدام الأمر seek وإذكر مرة أخرى هنا أن هذه الطريقة تستخدم للبحث عن تسجيلة في مجموعة التسجيلات من النوع Table ولا يمكن استعمالها مع باقي الأنواع، وتقوم هذه الطريقة بالبحث فقط وفقاً لفهارس الجدول المعرفة أو التي يمكن تعريفها أيضا برمجياً وقبل كل شيء لنلقي نظرة على فهارس جدول الموظفين كما في الصورة :

krajabi2.JPG

ولهذا قمنا بوضع اسم الفهرس PrimaryKey علما أننا نستطيع تغيير هذا الأسم في وضع تصميم الجدول ومن نافذة الفهارس كما في الصورة.

لاحظوا أيضا أن rstemployees.Index تدعى خاصية الفهرس

ومرة أخرى أذكر أن للكائن recordset ولاي كائن يوجد خصائص (properties ) و طرق (Methods) يعني أوامر.

السؤال الذي يطرح نفسه هنا ماذا يحدث لو لم نقم بضبط خاصية الفهرس قبل استخدام الأمر seek ، سينتج الخطأ التالي :

Operation invalid without a current index

وعلماً أنه يمكن البحث عن تسجيلة وفق فهرس يتألف من أكثر من حقل (حتى 13 حقلا) وسنأخذ مثال على ذلك لاحقاً بإذن الله.

3. الأن الوضع مرتب لإجراء البحث ويتم ذلك من خلال الطريقة (الأمر) method واسمها seek بالطرية التالية

rstEmployees.Seek "=", id

حيث id هي القيمة التي تم قراءتها والأن سنبحث عنها ويمكن البحث بعدة طرق "=" ، ">" ، "<" ، "=>" ، "=<"

4. بعد الأمر السابق وهو أمر البحث يتم عمل شيئين بشكل تلقائي وفي الخفاء وهما:

- يتم الإنتقال غلى التسجيلة التي وجدت حسب البحث (إن وجدت)

- يتم تعريف قيمة الخاصية nomatch بناء على النتيجة إذا وجد السجل يكون فيها false وإذا لم يوجد يكون فيها true

5. الأن الأمر اصبح في غاية البساطة ولأننا نبحث في مفتاح رئيسي فلا حاجة للبحث إلا مرة واحدة فإن وجد الرقم فالسجل موجود وإلا فغير موجود.

6. في نهاية العمل لا تنسوا دائما إغلاق مجموعة التسجيلات بإستخدام الأمر close.

أتمنى لكم وقتا سعيدا وممتعا مع هذا الدرس وإلى لقاء بإذن الله قريباً

مع الاحترام والتقدير

RecordSets.rar

تم تعديل بواسطه خضر الرجبي
  • Like 1
  • Thanks 1
قام بنشر

السلام عليكم ،

إخوان وأخواتي ، بارك الله فيكم جميعاً

في هذا الجزء من الدرس سيتم إلقاء الضوء على تقنيات طرق التعامل مع مجموعات التسجيلات المختلفة في فيجوال بيسك وهي بشكل من الجديد إلى القديم ADO و DAO و RDO :

في فيجول بيسك ، يتوفر هذه الواجهات (تقنيات اتصال) للوصول للبيانات :

1. ActiveX Data Objects (ADO)

2. Data Access Objects (DAO)

3. Remote Data Objects (RDO)

وكل من هذه الثلاثة تمثل كائن من كائنات الوصول للبيانات بوجوه مختلفة ، وباستخدام VBA بإمكانك برمجيا التحكم بالاتصال ، بنى الجمل ، والبيانات التي سيتم إرجاعها للاستخدام في التطبيق.

السؤال هو ؟ لماذا هناك 3 طرق للوصول للبيانات في الفيجوال بيسك ؟ من المعروف أن طريق الوصول للبيانات تتطور بشكل متواصل وكل طريقة من هذه الطرق تمثل مرحلة من المراحل الفنية في هذا التطور . الأخيرة (الأحدث) هي ADO ، والتي من خصائصها البساطة - ورغم البساطة الأكثر مرونة – من كلا RDO أو DAO . للمشاريع الجديدة ، ينصح بشدة اعتماد ADO كواجهة (تقنية) الوصول للبيانات. هذه النصيحة ليست من خضر الرجبي ولكن من ميكروسوفت نفسها وهنا المرجع http://msdn.microsoft.com/library/default....dwithrdodao.asp

أما بالنسبة لي فكما ذكرت سابقا أن أنصح الجميع بمعرفة القديم والجديد وقد وضعت المبررات لذلك وأنا ماض بتعريفكم على ADO و DAO بإذن الله كما وعدت سابقا.

لماذا نستخدم ADO ؟

تم تصميم ADO بأبسط مستوى اتصال في ميكروسوفت مع OLE DB ، و OLE DB توفر كفاءة عالية في الوصول إلى أي مصدر بيانات ، سواءً في قواعد البيانات العلائقية أو غير العلائقية (لعلمكم يوجد قواعد بيانات تسمى الشبكية و المهيكلة وهي الجيل السابق من قواعد البيانات) ، وكذلك من مصادر البيانات أنظمة الملفات والبريد الإلكتروني ، والبيانات النصية والرسومية ، وكائنات الأعمال المخصصة ، وغيرها من المصادر.

ADO صممت لملائمة الحد الأدنى من التراسل عندما نتعامل مع بيئة وسيناريوهات الإنترنت ، وأيضا تضع الحد الأدني من الطبقات بين واجهة التطبيق النهائية يعني للمستخدم وبين مصدر البيانات – كل ذلك ضمن واجهة خفيفة ذات كفاءة عالية. وكذلك ADO تستعمل طرق محادثة وخصائص مشابهة لتلك في DAO و RDO ، مع تبسيط منطق هذه الطرق وذلك من أجل التسهيل على المستخدم .

ماذا بشأن DAO و RDO ؟

من أجل التوافقية (compatibility) ولدعم المشاريع السابقة استمرت فيجوال بيسك بدعم DAO و RDO للمشاريع القائمة.

مقارنة ADO مع RDO و DAO :

ADO ليست متواقة-الكود تلقائيا مع تطبيقاتك التي تستعمل طرق الوصول للبيانات السابقة . بينما كبسلة (encapsulation) تتضمن العمليات المتوفرة في كل من ADO و RDO ، يجب عليك تحويل الكثير من عناصر اللغة لاستعمال قواعد ADO في مشروع كان يستخدم DAO إن أحببت التحويل. في بعض الحالات ، هذا يعني تحويل بعض الإقترانات فقط ، وفي البعض الأخر قد تحتاج لبناء التطبيق كاملا من جديد باستخدام خصائص ADO الجديدة.

DAO (Data Access Objects) : هي أول واجهة كائنات-مرئية object-oriented تعامل به محرك قاعدة بيانات ميكروسوفت Jet والتي مكنت مستخدمي فيجوال بيسك من الوصول إلى الجداول الأكسيس مباشرة وكذلك لقواعد بيانات أخرى من خلال ODBC . لا شك أن DAO هي الأنسب لتطبيق يعمل على جهاز واحد وكذلك الأنسب لمؤسسة صغير منفردة.

RDO (Remote Data Objects) : هو كائن-مرئي يستخدم في التواصل مع ODBC بشكل موحد ومستثمرا لسهولة DAO، للكائن RDO حدوديات ، ورغم ذلك ، أثبت أفضلية استعماله مع بعض المحركات المشهورة مثل SQL Server, Oracle .

ADO هو الجيل الجديد واللاحق DAO/RDO . عمل ADO أقرب ما يكون من RDO ، وعادة يوجد الكثير من التشابه في طرق الاستعمال. نستطيع القول بأن ADO حل محل الكائنين معا . ومن الممكن في البداية أن تظن أن التعامل مع ADO صعبا إلا أنك ستكتشف بإن طريقة بناءه المهيكلة ستجعل من السهولة بمكان التعامل مع ببساطة شديدة .

من المهم ملاحظة أيضا أن ADO حالياً لا يدعم جميع إقترانات DAO ، وهو يحتوي اسلوب الدعم أكثر المتوفر في RDO للتفاعل مع مصادر بيانات OLE DB بالإضافة لدعم المصادر البعيدة وكذلك تكنولوجية DHTML.

بشكل عام ، ربما ما زال مبكرا الرحيل إلى استعمال ADO بشكل كامل (بإستثناء أولئك الذين يستعملون ODBCDirct) ، حيث أن ADO لا تدعم بشكل كامل data definition (DDL)، المستخدمين, المجموعات ، على كل الأحول إذا كنت تستخدم DAO فقط في تطبيقات client-server الخادم-الزبون ولا تعتمد عليه في لغة تعريف البيانات بشكل اساسي ، فربما حان الوقت.

خلاصة القول : وهذا رأيي الشخصي ، أنه قد حان الوقت بالتأكيد لمن لم يعرف عن الاثنين للتعرف على الاثنين معا حتى يواكب القديم والحالي والقادم من التطبيقات .

ولكم مني كل الاحترام والتقدير

  • Like 1
  • Thanks 1
قام بنشر

السلام عليكم

إخواني وأخواتي ، بارك الله فيكم جميعاً

قبل أن نكمل درسنا في التعمق في طريقة التعامل مع مجموعات التسجيلات وعرض طرق أخرى لتعريف مجموعة التسجيلات recordset بأستخدام الكيان DAO ، أود أن نلقي الضوء قليلا وعلى نفس المثال السابق وهو الوصول إلى سجل محدد ولكن هذه المرة باستخدام تقنية ADO ، ولكن قبل عمل ذلك أود أن أشير إلى أهمية الانتباء إلى المراجع حيث مرجعي ADO و DAO يوجد بهما نفس التسمية للكيانات مثل recordset وكيف نتغلب على تشابه التسمية.

kr1.JPG

في الصورة السابقة ومن شاشة محرر فيجوال بيسك (ALT+F11) ... ثم tools ... ثم References يظهر لنا الصندوق الحواري كما في الصورة لاحظوا أننا اخترنا DAO وكذلك ADO في نفس الوقت وهذا يعني أنه يمكن استخدام جميع الكيانات فيهما الأثنين ومنها الكيان recordset فماذا سيعتبر في البرنامج (الوحدة النمطية) هل سيتبع إلى DAO أو إلى ADO ، في الحقيقة أن أسهل طريقة وحتى لا يحدث لبس هي تعريفه بالشكل التالي ADODB.Recordset أو DOA.Recordset أم أذا عرفنه بدون تحديد فهو سيتبع للمرجع الذي يظهر أولا وفي هذه الحالة كما في الصورة سيتبع إلى DAO حيث هو المعرف قبل ADO.

الآن أنتقل بكم مباشرة إلى تطبيق المثال المكافىء للمثال الأول وعلى نفس القاعدة السابقة قاعدة الموظفين التي تم إرفاقها وللحصول على معلومات الموظف مباشرة ولكن بإستخدام تقنية ADO .

Private Sub example1_Click()

Dim Cnn As ADODB.Connection
Dim rstEmployees As ADODB.Recordset
Dim strCnn As String

Set Cnn = New ADODB.Connection
strCnn = CurrentProject.Connection
Cnn.Open strCnn

Set rstEmployees = New ADODB.Recordset
rstEmployees.Open "employees", Cnn, 3, 1, adCmdTableDirect 'read only and allow indexing
  
id = InputBox("أدخل رقم الموظف")
  
rstEmployees.Index = "PrimaryKey"

rstEmployees.Seek id, adSeekFirstEQ

If rstEmployees.EOF Then
 MsgBox "الرقم غير موجود"
Else
 MsgBox rstEmployees!empfirst & " " & rstEmployees!empfamily
End If

rstEmployees.Close
Set Cnn = Nothing
Set rstEmployees = Nothing

End Sub
الملاحظات : 1. تمهيدا للوصول للجدول employees الموجود في قاعدة البيانات الحالية وليست في مصادر بيانات خارجية أو قاعدة أخري نعرف أولا ما يسمى نص الإتصال connection string وهو مصدر البيانات وهنا الأمر في غاية البساطة فهو في نفس القاعدة ولذا أشرنا له بالنص currentproject.connection والمكافئة تماما في تقنية DAO للنص CurrentDb ومن الضروري جدا فتح الاتصال وهذا تم في الجملة Cnn.Open strCnn 2. ثم نقوم بفتح (تعريف) مجموعة التسجيلات والتي تتم من خلال الخاصية OPEN كما في rstEmployees.Open "employees", Cnn, 3, 1, adCmdTableDirect 'read only and والشكل العام لخاصية الفتح هو recordset.Open Source, ActiveConnection, CursorType, LockType, Options علماً أن كلمة cursor هنا يعنى بها عنصرا من قاعدة البيانات التي تتحكم في التنقل بين السجلات ، تعديل البيانات ، وظهور التغيرات من المستخدمين للقاعدة. وطبعا يوجد هنا كما في DAO أيضا أربعة طرق مختلفة لفتح مجموعة التسجيلات وهي CursorType : adOpenDynamic = 2، adOpenForwardOnly= 0 ، adOpenKeyset = 1 ، adOpenStatic = 3 ، والتي سنتعرض لها بالتدريج ، ما تم استخدامه في هذا المثال هو 3 وهو يسمى static cursor وهو عبارة عن نسخة ساكنة عن السجلات للوصول وإيجاد البيانات دونما الأهتمام برؤية الإضافات والتغييرات والحذف الآني من المستخدمين. LockType : نوع إقفال السجلات وما استخدامناه في مثالنا هو 1 adLockReadOnly ويعني أن البيانات للقراءة فقط ولا نستطيع التعديل عليها . options : الخيارت التي تحدد كيف سيقو مزود البيانات بمعالجتها وفي مثالنا استخدمنا adCmdTableDirect وبهذا الخيار فقط يمكن استعمال الخاصية seek في ADO وقيمة هذا الثابت ، يعني adCmdTableDirect هي 512 . تذكروها جيدا حيث لا يوجد طريقة غيرها . 3. الآن البيئة مهيئة تماما لما نريد تحقيقه في المثال نقوم بتحديد الفهرس كما في خاصية الفهرس
rstEmployees.Index = "PrimaryKey"

ولا تنسوا حكاية اسم الفهرس فهي نفس الحكاية التي تم شرحها أعلاه في DAO .

4. ثم نقوم بقراءة رقم الموظف وحاولة الوصول إليه من خلال الخاصية

rstEmployees.Seek id, adSeekFirstEQ

5. لاحظوا هنا الفرق بين هذه الطريقة وطريقة DAO حيث المعاملات تم عكسها علما أن عمليات المقارنة كانت هناك "=" بينما هنا أصبحت كما يلي وحسب مثالنا :

adSeekFirstEQ 1 البحث عن أول موظف له الرقم المحدد.

6. بالنسبة nomatch لا توجد هذه الخاصية في ADO وعوضا عنها نستخدم فكرة أن البحث إذا لم يسفر عن نتيجة فإن مؤشر القراءة الوهمي سيصبح نهاية الملف وهكذا نتصرف ونسأل عن خاصية نهاية الملف rstEmployees.EOF إذا كانت true فهذا يعني أننا لم نجد أي سجل يوافق البحث .

7. هذا كل شيء لا تنسوا إغلاق مجموعة التسجيلات في نهاية العمل كما فعلنا أيضا مع DAO .

أليست البرمجة رائعة ؟؟

مع احترامي وتقديري لكم جميعاً.

FindEmp_ADO_DAO.rar

  • Like 1
  • Thanks 2
قام بنشر

السلام عليكم ورحمه الله وبركاته ،،،

الله يعطيك العافيه على المشاركة القيمة التي تفيد المبرمج ،،، جزاك الله خير الجزء ،،، وبارك الله في علمك وزادك اكثر فأكثر ،،،

مع تحياتي للجميع ،،،

عبدالمانع

قام بنشر (معدل)

السلام عليكم

أخي عبد المانع :fff: ، أشكرك

إخواني وأخواتي ، بارك الله فيكم جميعاً

سنتابع درسنا في Recordsetclone استنساخ مجموعة التسجيلات Recordset

وفي هذا الدرس سنتعلم كيف نتعامل مع مجموعة التسجيلات المرتبطة مع نموذج والتي يمكن تحديدها من خاصية record source مصدر السجل في النموذج في وضع التصميم .

هذه المجموعة من نوع Dynaset وهو النوع الثاني في تقنية DAO والتي يكافئها في ADO خاصية keyset cursor وهي مجموعة السجلات التي يمكن الأضافة عليها أو التغيير بها أو الحذف منها والمتعلقة بجدول واحد أو مجموعة جداول .

من المهم ملاحظة أن نوع مجموعة التسجيلات التي يتم تعريفها في وضع التصميم في قاعدة البيانات mdb. هي بشكل تلقائي DAO Recordset ، أما في مشروع أكسيس فتكون ADO Recordset.

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

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

Private Sub example1_Click()

Dim rstEmployees As DAO.Recordset
  
Set rstEmployees = Me.Form.RecordsetClone

id = InputBox("أدخل رقم المسئول")

C = 0

MsgBox "عدد الموظفين " & rstEmployees.RecordCount

rstEmployees.MoveFirst

Do While Not rstEmployees.EOF
If rstEmployees!EmpHead = id Then C = C + 1
rstEmployees.MoveNext
Loop

If C = 0 Then
 MsgBox "الموظف صاحب الرقم  " & id & "ليس مسؤولا عن أحد"
Else
 MsgBox " عدد الموظفين الذين بأمرة هذا المسؤول " & C
End If

rstEmployees.Close

End Sub

ملاحظات :

1.

Set rstEmployees = Me.Form.RecordsetClone

في هذا الأمر تم استنساخ مجموعة التسجيلات المرتبطة بالنموذج وهي في مثالنا سجلات الموظفين من جدول الموظفين وتم تعيينها لمجموعة التسجيلات rstrecordset التي ليس لها علاقة نهائيا في المجموعة المرتبطة بالنموذج.

2. تم عمل حلقة دورانية تنتهي بالوصول إلى أخر سجل في المجموعة المستنسخة وخلالها نقوم بزيادة العداد بناء على تحقق الشرط الذي بواصطته نحدد أن الموظف الذي أدخلنا رقمه بالمتغير id هو مسؤولا أو لا عن الموظف الذي وصلنا عنده في دورة الحلقة.

3. وفي النهاية يتم بناء على قيمة c وهي عدد الموظفين الذين تم احصائهم طباعة النتيجة.

مع الاحترام والتقدير

RecordsetLesson.rar

تم تعديل بواسطه خضر الرجبي
  • Like 2
قام بنشر (معدل)

السلام عليكم

إخواني وأخواتي ، بارك الله فيكم

لتأخذ وقتا مستقطعاً من درس مجموعة التسجيلات والوقوف قليلاً مع الملف المرفق للفائدة والأهمية.

مع الاحترام

Functions.rar

تم تعديل بواسطه خضر الرجبي
  • Like 1
قام بنشر

السلام عليكم

إخواني وأخواتي ، بارك الله فيكم جميعاً

درسنا اليوم حول نفس الموضوع السابق وهو استنساخ مجموعة التسجيلات بواسطة Recordsetclone ولكن هذه المرة مع ADO .

قد يظن البعض أن الأمر في غاية البساطة وذلك باستخدم نفس المثال السابق مع تغيير السطر التعريف الأساسي

Dim rstEmployees As DAO.Recordset

إلى

Dim rstEmployees ADODB.Recordset

حسناً هكذا يبدو الأمر ، جربوه ولن ينجح حيث ستحصلون في الجملة

Set rstEmployees = Me.Form.RecordsetClone

على الخطأ Type mismatch أي أن الأنواع غير متوافقة يعني المجموعة المستنسخة من نوع أخر وهذا صحيح ! ، أنسيتم السطرين السابقين باللون الأحمر ، فأنا لم ألونهما جزافاً واعيدهما هنا مرة أخرى للتذكير

من المهم ملاحظة أن نوع مجموعة التسجيلات التي يتم تعريفها في وضع التصميم في قاعدة البيانات mdb. هي بشكل تلقائي DAO Recordset ، أما في مشروع أكسيس فتكون ADO Recordset

إذاً هذا هو السبب أن مصدر السجلات الذي عرفنه في النموذج والذي سيمثل مجموعة التسجيلات سيكون من النوع DAO . حسناً ، الحل بسيط نرجع للمراجع ونجعل مرجع ADO يسبق مرجع DAO بالتعريف وهكذا يتم تحديد نوع مجموعة التسجيلات من نوع ADO ، جربوه وللأسف لن ينجح ، و ياليت الحل كان بهذه البساطة!

ماذا نجري الأن ؟ لم يبقى لنا إلا أن نفعل شيء واحد ونأمل أن ينجح وهو حذف المرجع DAO (عدم اختياره من ضمن المراجع) ، جربوا ذلك ، ويا للعجب ، حتى أننا بعد حذف المرجع كاملا لم يتم تعريف مجموعة التسجلات المرتبطة بالنموذج من نوع ADO .

ماذا سنعمل إذن ، أولا سنحفظ القاعدة التي في اللون الأحمر حتى لا نتعب أنفسنا أكثر حيث لا يوجد طريقة نهائيا في وضع التصميم لجعل النموذج يرتبط بمجموعة تسجيلات غير DAO .

ثأنيا ، لا تبتأسوا كثيرا حيث يوجد حل وهو رائع جدا وهو كما يلي وأيضاً يمكن اعتباره قاعدة ويجب حفظه غيباً.

إذا أردنا أن نجعل مجموعة التسجيلات لنموذج في قاعدة mdb. تعمل بتقنية ADO يجب عمل الخطوات الثلاث التالية.

1. في وضع التصميم للنموذج نلغي مصدر السجل Record source للنموذج (أي نجعله بدون مصدر) .

2. في حدث الفتح للنموذج نضع الكود التالي بدون تغيير سوى بمصدر السجل الذي هو في مثالنا جدول employees :

Private Sub Form_Open(Cancel As Integer)
Dim rst As ADODB.Recordset, cn As ADODB.Connection
Set rst = New ADODB.Recordset
rst.ActiveConnection = CurrentProject.Connection
rst.CursorType = adOpenDynamic
rst.CursorLocation = adUseClient
rst.Open "employees", , adOpenKeyset, adLockOptimistic, adCmdTable
Set Me.Recordset = rst
End Sub
3. في حدث الإغلاق للنموذج نضع الكود التالي :
Private Sub Form_Close()
 Dim cn As ADODB.Connection
 Set cn = Me.Recordset.ActiveConnection
 cn.Close
 Set cn = Nothing
End Sub

وبعدها سيختفي الخطأ Type mismatch الذي تحدثنا عنه في بداية الدرس

وإليكم الحل كاملا كما طرحته تماما هنا في المرفق التالي :

مع احترامي وتقديري لكم

RecordsetLesson2.rar

  • Like 2
  • Thanks 2
قام بنشر (معدل)

السلام عليكم

إخواني ، بارك الله فيكم

بينما أنتم في انتظار درس مجموعات التسجلات التالي ، ارجو منكم مطالعة هذا الدرس الخفيف والمهم

أولا يوجد 3 أنواع من القيم يجب أن نميز بينها :

null : تشير أن المتغير أو الحقل يحتوي على بيانات غير صحيحة .

empty : تشير أن المتغير لم يتم إعطاءه قيمة إبتدائية حتى ولو تم تعريفه

"" : تعني أن المتغير له قيمة ولكنها النص الفارغ.

يعني لكل واحدة معناً مختلف تماما عن الأخرى ، وحتى نفهم الفرق جيدا للنظر إلى المثال التالي :

Private Sub example_Click()
1)    Dim x As Variant
2)    If IsNull(Null) Then MsgBox "Null" Else MsgBox "not null"
3)    If IsEmpty(Empty) Then MsgBox "empty" Else MsgBox "not empty"
4)    If IsEmpty("") Then MsgBox "empty" Else MsgBox "not empty"
5)    If IsNull("") Then MsgBox "Null" Else MsgBox "not null"
6)    If IsNull(x) Then MsgBox "Null" Else MsgBox "not null"
7)    If IsEmpty(x) Then MsgBox "empty" Else MsgBox "not empty"
8)    x = ""
9)    If IsNull(x) Then MsgBox "Null" Else MsgBox "not null"
10)    If IsEmpty(x) Then MsgBox "empty" Else MsgBox "not empty"
11)    x = Null
12)    If IsNull(x) Then MsgBox "Null" Else MsgBox "not null"
13)    x = Empty
14)     If IsNull(x) Then MsgBox "empty" Else MsgBox "not empty"
15)     x = Null
16)     If IsEmpty(x) Then MsgBox "empty" Else MsgBox "not empty"
End Sub

في السطر الأول تم تعريف المتغير x

في السطر الثاني ستكون النتيجة Null وهذا يعني أنه يوجد قيمة معروفة في أكسيس تسمى Null

في السطر الثالث ستكون النتيجة Empty وهذا يعني أن هناك قيمة معروفة في أكسيس تسمى Empty

في السطر الرابع ستكون النتيجة not empty لأن "" هو ثابت مع أنه النص الفارغ إلا أنه يعتبر empty حيث أني empty كما ذكرت تعني عدم تعريف المتغير وليس الفراغ.

في السطر الخامس النتيجة not null لأن القيمة "" لها معناً وهو النص الفارغ.

في السطر السادس النتيجة not null ، صحيح أنه تم تعريف المتغير x ولم يتم تحديد قيمة ابتدائية له وهذا لا يجعل قيمته Null لأنه لا يحتوي على بيانات سواءً صحيحى أو غير صحيحة.

في السطر السابع النتيجة empty حيث أن المتغير x منذ تعريفه لم يتم اسناد قيمة له حتى الآن.

في السطر الثامن في هذه الجملة تم اسناد قيمة النص الفارغ "" للمتغير x

في السطر التاسع وبكل تأكيد هنا النتيجة ليست null حيث أنه يوجد قيمة للمتغير x وهي النص الفارغ ""

في السطر العاشر وهنا أيضا النتيجة ليست empty حيث يوجد قيمة تم اسنادها للمتغير x وبغض النظر عن ما هي .

في السطر الحادي عشر ، شيء رائع الآن أصبحت قيمة x = null

في السطر الثاني عشر وهنا بالتاكيد ستكون النتيجة null

في السطر الثالث عشر واللآن لاحظوا بدقة ماذا سنفعل جعلنا قيمة x = empty

في السطر الرابع عشر ، هنا ربما تستغربون من النتيجة فالبرغم من قيمة x هي empty من الجملة السابقة إلا أن النتيجة not empty ! أتعرفون لماذا ؟ لأن Isempty يسأل فيما إذا كان المتغير اسند له قيمة أو لا بغض النظر عن القيمة حتى ولو كانت empty.

في السطر الخامس عشر وأيضا مرة أخرى نجعل قيمة x= null وذلك لأتبت لكم القاعدة السابقة

في السطر السادس عشر ، لاحظو وهنا أيضا قيمة x أيضا not empty لأنه تم اسناد قيمة للمتغير x وهي null.

كيف نحفظ هذه القواعد بعد أن فهمنها وجربنا نتائجها :

لا تدعو ترجمة المعنى الحرفية تخدعكم حيث أن

null ، empty ، "" إذا ترجمت ستعطي معناً واحدأ وهو (لا شيء أو فراغ) هذا الكلام خطأ وهو الخطأ الذي يقع به الكثيرين .

تذكروا دائما التعريفات التي بدأت فيها الدرس ولن تخطئوا باستخدام هذه القواعد أبداً.

مرفق التطبيق .

مع الاحترام والتقدير

Null_Empty_DblQoutes.rar

تم تعديل بواسطه خضر الرجبي
  • Like 1
  • Thanks 1
قام بنشر

السلام عليكم

أخواني وأخواتي ، بارك الله فيكم جميعا

الأن ننتقل لدرس تحديث السجلات بتقنية DAO

في مثالنا التالي سنقوم بوضع ملاحظة لجميع الموظفين الذين يعملون في قسم الإدارة التي رقمها 10 والملاحظة هي أن الموظف مسافر في مهمة.

Private Sub Command0_Click()
Dim db As Database
Dim rst As DAO.Recordset

Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT EmpNotes FROM Employees WHERE DepId='10'; ", dbOpenDynaset)

MsgBox rst.RecordCount & " هذا العدد لا يشير إلى عدد السجلات "

rst.MoveLast
rst.MoveFirst
MsgBox rst.RecordCount & " عدد السجلات في المجموعة المختارة "

Do While Not rst.EOF
 rst.Edit
 rst!EmpNotes = "مسافر في مهمة"
 rst.Update
 rst.MoveNext
Loop
rst.Close
End Sub
ملاحظات : 1. في جملة الفتح نلاحظ أننا نستطيع استعمال جملة sql مباشرة وفي هذه الحالة نوع مجموعة التسجيلات يكون Dynaset. 2. نلاحظ أن العدد الذي سنحصل عليه من recordcount قبل عملية الذهاب إلى أخر سجل movelast وثم الرجوع إلى أول سجل هو ليس عدد السجلات الصحيح ، وحتى نحصل على عدد السجلات الصحيح يجب إتباع هذا الأسلوب دائما وبعدها فقط نستطيع أن نعرف عدد السجلات الناتجة من التعريف. 3. قبل تعديل أي حقل في مجموعة التسجيلات يجب جعل السجل في وضع التعديل edit وبعد التعديل يجب عمل Update (تحديث) وإلا لن يتغير شيء. 4. يمكن كتابة الأوامر بدون ذكر اسم مجموعة التسجيلات كل مرة باستخدام with كما يلي
Private Sub Command0_Click()
Dim db As Database
Dim rst As DAO.Recordset

Set db = CurrentDb
Set rst = db.OpenRecordset("SELECT EmpNotes FROM Employees WHERE DepId='10'; ", dbOpenDynaset)
With rst
MsgBox .RecordCount & " هذا العدد لا يشير إلى عدد السجلات "

.MoveLast
.MoveFirst
MsgBox .RecordCount & " عدد السجلات في المجموعة المختارة "

Do While Not .EOF
 .Edit
 !EmpNotes = "مسافر في مهمة"
 .Update
 .MoveNext
Loop
.Close
end with
End Sub

يعني عمل with هو تمكيينا من الرجوع للخصائص العائدة لمجموعة التسجيلات بدون كتابة اسم مجموعة التسجيلات rst في كل مرة.

سيلحق هذا الدرس (بإذن الله) نفس المثال ولكن بإستخدام تقنية ADO .

مع الاحترام والتقدير

Edit_Update_DAO.rar

  • Thanks 1
قام بنشر

السلام عليكم

إخواني وأخواتي ، بارك الله فيكم جميعا ،

ونكمل درسنا مع نفس المثال السابق ولكن بتقنية ADO

المثال يصبح كما يلي :

Private Sub Command0_Click()
Dim Cnn As ADODB.Connection
Dim rst As ADODB.Recordset
Dim strCnn As String

Set Cnn = New ADODB.Connection
strCnn = CurrentProject.Connection
Cnn.Open strCnn

Set rst = New ADODB.Recordset
rst.Open "SELECT EmpNotes FROM Employees WHERE DepId='10'; ", Cnn, adOpenKeyset, adLockOptimistic

MsgBox rst.RecordCount & "  عدد السجلات  هنا صحيح وهو  "

rst.MoveLast
rst.MoveFirst
MsgBox rst.RecordCount & " عدد السجلات في المجموعة المختارة "

Do While Not rst.EOF
rst.Edit
rst!EmpNotes = "مسافر في مهمة"
rst.Update
rst.MoveNext
Loop
rst.Close
End Sub  

الملاحظات :

1. كما ذكرنا سابقا Dynaset في DAO يقابلها Keyset في تقنية ADO هذا بالنسبة للتعريفات .

2. مشكلة أسلوب الحصول على عدد السجلات في المجموعة التي اضطررنا إلى الذهاب فيها إلى أخر سجل ثم إلى أول سجل ، قد اختفت هنا ولا حاجة سوى للذهاب إلى أول سجل قبل الدخول في الحلقة ولكنني أبقيتها هنا حتى تتأكدوا من ذلك بأنفسكم .

3. بالنسبة لإستخدام with أو عدم استخدامها لا علاقة لها بتقنية ADO أو DAO ويبقى الهدف من استخدمها ان استخدمت كما ذكرت سابقا هو تسهيل عملية الوصول إلى الخصائص مباشرة بكتابتها بعد النقطة وبدون كتابة اسم مجموعة التسجيلات كما أوضحت ذلك في الدرس السابق.

4. لا يوجد هنا خاصية Edit. ولا داعي لإستخدامها كما في DAO أما بالنسبة لخاصية التحديث Update. فسواءً تم وضعها أو لا النتيجة واحدة.

أملا لكم التوفيق في فهم الدروس .

في الدرس القادم سنتحدث عن خاصية Bookmark وأهميتها.

المرفق التالي يشمل الست أمثلة التي تم مناقشتها حتى الأن.

مع الاحترام والتقدير

RecordsetLesson_6_Examples.rar

  • Thanks 1
قام بنشر (معدل)

جزاك الله ألف ألف خير

وبارك الله فيك وفي علمك القيم هذا

وجعل ذلك في ميزان حسناتك

عندي بعض الأسئلة أتمنى أن تعطيني الإجابة بارك الله فيك ؟

السؤال الأول هو عن RecordSetClone

ذكرت لنا في شرحك المميز بأن:

RecordSetClone هو استنساخ مجموعة التسجيلات Recordset

أرجو أن توضح لنا ما معنى استنساخ مجموعة التسجيلات

السؤال الثاني

ما وظيفة EOF كما في المثال الأخير الذي ذكرته لنا ؟

Do While Not rst.EOF
rst.Edit
rst!EmpNotes = "مسافر في مهمة"
rst.Update
rst.MoveNext
Loop[/php]

ونحن في انتظار المزيد من المعلومات القيمة التي ستتعطينا أياه الله يجزاك خير

:rol::rol::rol:

تم تعديل بواسطه بو يوسف الراشد
قام بنشر

السلام عليكم

أخي أبا يوسف الراشد ، بارك الله فيك

إبتداءً ، أود أن أتقدم لك بجزيل الشكر على اهتمامك بالموضوع وتشجيعك ودعائك الكريم.

السؤال الأول هو عن RecordSetClone

الأستنساخ هنا يعني نسخة عن مجموعة التسجيلات ليس إلا ولكن المعنى اللفظي clone يترجم هكذا ، أما عن الأهداف فقد ذكرتها وألخصها مرة أخرى هنا :

1. نستخدم هذه الطريقة للوصول إلى خصائص مجموعة التسجيلات recordset ، التي لا يوفرها لنا النموذج .

2. استقلالية مؤشر هذه المجموعة عن مجموعة التسجيلات مما يتيح لنا عمل أشياء على سجلات النموذج بدون ظهور أثر هذه الأشياء في واجهة النموذج.

السؤال الثاني : ما وظيفة EOF كما في المثال الأخير الذي ذكرته لنا ؟

تخيل أننا عند أخر سجل وقمنا بطلب أمر الأنتقال إلى السجل التالي movenext بهذه الحالة سيحدث خطأ وهو أنه لا يوجد سجل No current Record . هذا من ناحية ومن ناحية أخرى نحن نبدأ في التنقل بين السجلات من أول سجل وحتى أخر سجل والأسلوب الذي نتبعه في الخروج من الحلقة هو عند وصولنا إلى أخر سجل لذا ما لم تكن قيمة مؤشر السجلات eof يعني أخر سجل ، فإننا سنبقى في الحلقة .

ويوجد ايضا قيمة أخرى لمؤشر السجلات وهي bof وتشير إلى بداية أول سجل وتعمل بمنطقي معاكس تماما لمنطق eof.

يعني بطريقة أوضح تكون قيمة eof = true عندم يكون مؤشر التسجيلات عند أخر سجل

وتكون قيمة bof = true عندما يكون مؤشر التسجيلات عند أول سجل وعدا ذلك تكون القيمتين false. وبناء عليه يتم بناء المنطق البرمجي لما سنفعله حسب الحالية وطريقة التنقل من أول إلى اخر تسجيلة أو العكس .

مع الاحترام والتقدير

  • 2 weeks later...
قام بنشر

استخدام معلمات التسجيلات Bookmarks

في لغة البرمجة VBA ، في الغالب في البرامج نحن نتعامل كما لاحظنا أعلاه مع مجموعة جزئية من السجلات وليس مع كل السجلات ، وبما أن المصدر الأساس لهذه التسجيلات يمكن أن يتغير في أي لحظة وخصوصا إذا كان البرنامج يعمل في بيئة تعدد المستخدمين ، وخصوصا في عمليات الحذف والأضافة ن فأنه لا يوجد رقم مطلق لك تسجيلة ، يمكن استخدامه للعودة للتسجيلة، وبدل ذلك ولهذا نستخدم بما يسمى معلمات التسجيلات Bookmarks ، بهدف تحديد (تعليم) تسجيلة معينة للرجوع لها.

ويتكون معلم التسجيلة من سلسلة نصية مولدة من الأكسيس لكل تسجيل ويمكن إسناد قيمتها لمتغير نصي (string) ، لحفظها والعودة لها لاحقا.

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

وفي مثالنا التالي ، نريد أن نصمم زر أمر بحيث ينقلنا إلى المسؤول عن الموظف .

أملا أن أكون بهذا قد ألقيت بعض الضوء على موضوع مجموعات التسجيلات ، ومتمنيا للجميع السرور والسعادة في الدنيا والاخرة ، والله ولي التوفيق ، وأخر دعواهم أن الحمد لله رب العالمين.

مع الاحترام

RST_7_Lessons.rar

قام بنشر

السلام عليكم

أشكركما أخواي بو يوسف الراشد وأخي ثبيت عرب وبارك الله فيكما

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

قريبا بإذن الله سيكون هناك سلسلة دروس جديدة ولكن بطريقة مختلفة (خليها مفاجئة)

مع احترامي وتقديري لكما

  • 1 year later...
قام بنشر

استاذنا الفاضل / خضر الرجبي :fff:

جزاك الله خير الجزاء على هذه الدروس الرائعة وعلى هذا المجهود الكبير ... جعله الله في موازين حسناتكم

لقد قمت بصياغة هذا الشرح الرائع الى كتاب Pdf ليتمكن الجميع من اقتنائه ولاستفادة منه وذلك بعد اذنك طبعاً

اسأل الله ان اكون وفقت في ذلك

وتفضلوا بقبول فائق الاحترام والتقدير،،،

VBA_Lessons.rar

زائر
هذا الموضوع مغلق.
  • تصفح هذا الموضوع مؤخراً   0 اعضاء متواجدين الان

    • لايوجد اعضاء مسجلون يتصفحون هذه الصفحه
×
×
  • اضف...

Important Information