07-09-20, 10:13 AM
بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته اعضاء المنتدى الكرام
الموضوع بلغة C#
لايخفى عليكم اخواني الكرام اهمية وقوة تقنية LINQ ، فهذه التقنية جعلت التعامل مع البيانات اسهل بكثير جدا ، فما كان يتطلب عديد السطور لانجازة اصبح الان يكفي سطر واحد لعمله
تقديم :
تقنيه LINQ ليست فقط لقواعد البيانات ، في الحقيقة هذه التقنيه تتعامل مع اي فئة تتضمن الواجهة IEnumerable اي قابلة للعد ، وهذا يشمل المصفوفات Arrays و القوائم generic lists
تتضمن هذه الواجهة طرق كثيرة جدا للتعامل مع البيانات ، مثل Select , Where , Aggregate وغيرها الكثير والكثير
لذلك فكرت انه من باب التطبيق نقوم بعمل مثال يقوم بانشاء استعلام SQL بناء على بيانات الجدول المختارة من المستخدم ، او ما يصطلح الاخوة على تسميته "صانع اكواد"
ويجب قبل البدأ ان اخبركم ان الهدف من هذا المثال هو التدرب على استخدام LINQ وليس هو شرح كيفية عمل برنامج صانع اكواد ، فهذا موضوع قد قتل بحثا من جانب الاخوة الكرام
ولاجل الوصول الى ذلك بابسط طريقة ممكنة هناك بعض المفاهيم التي يجب ان نتفق عليها اولا :
مفاهيم اساسية خارج LINQ :
المطلوب :
قيمة من نوع String تمثل نص الاستعلام بالشكل التالي حسب الصفوف المختارة :
البداية :
نبدأ بتصميم بسيط يؤدي الغرض :
لاحظ الداتا جريد فيو قمنا باضافة 4 اعمدة لها عبارة عن :
دعونا اولا نفكر فيما سنحتاجه ،
صيغة الاستعلام التي نريدها تتكون من كلمات ثابتة : "SELECT" و "FROM" و "WHERE"
وكلمات مغيرة : اسماء الحقول المختارة بعد SELECT وكذلك الشروط الموضوعة بعد WHERE وكذلك اسم الجدول
طيب لذلك سنقوم بتعريف 4 متغيرات من نوع String
هيا بنا في حدث btnGenerateSql.Click نعرف متغير اسم الجدول ونسند له قيمة من مربع النص الخاص باسم الجدول محاط بالاقواس [] :
كيف نحصل على القيمة المطلوبة للمتغير selects ؟
طيب نبدأ العمل الحقيقي الان ، نريد الحصول على صفوف الداتا جريد فيو على شكل IEnumerable من نوع DataGridViewRow لنتمكن من استخدام طرق LINQ عليها ،
لفعل ذلك نستخدم الطريقة Cast ونمرر لها النوع DataGridViewRow :
جميل جدا ، الان ركزو معي جيدا ، نريد اختيار الصفوف المختارة فقط كجزء من Select ، اي الصفوف التي فيها قيمة الخلية الثانية ب True ،
لفعل ذلك نحن بحاجة الى الطريقة Where ، التي هي دالة الاختيار ، وظيفتها انها تختار من عناصر بيانات العناصر التي توافق شرط معين ، تقبل مدخل تعبير لمدا يمثل الشرط الذي يتم الاخيار بناء عليه ، وهو في هذه الحالة قيمة الخلية الثانية من الصف الحالي x.Cells(1).Value
الان حصلنا على الصفوف المطلوبة فقط ، جميل جدا نريد الان الحصول منها على اسماء الاعمدة المطلوبة ( قيمة الخلية الاولى في الصف ) محاطة ب [] ،
لفعل ذلك نستخدم الدالة Select التي تسمي دالة التحويل ، وظيفتها انها تحول كل العناصر التي تطبق عليها الى صورة اخرى ، في حالتنا نريد تحويل عناصر صفوف الداتا جريد فيو DataGridViewRow الى قيم نصية String تمثل اسماء الاعمدة ، الدالة تقبل مدخل تعبير لمدا يمثل التحويل المطلوب على كل عنصر ، وهو في هذه الحالة قيمة الخلية الاولى محاطة باقواس $"[{x.Cells(0).Value}]"
طيب جميل جدا الان ماذا اذا لم يختار المستخدم اي صف ؟ في هذه الحالة تكون القائمة فارغة ، نريد في هذه الحالة ان تكون القيمة الافتراضية "*" هي العنصر الوحيد ، يعني في حالة لم يتم اختيار صف معين نحن سنعيد القيمة * التي تعني كل الاعمدة في SQL ،
لفعل ذلك نستخدم الدالة DefaultIfEmpty التي وظيفتها انها ترجع بعنصر وحيد عبارة عن القيمة الافتراضية التي تمررها لها في حالة كانت القائمة التي تطبق عليها فارغة ، في هذه الحالة نمرر لها القيمة "*"
طيب الان جميل جدا جدا جدا ، معنا قائمة فيها كل اسماء الاعمدة المختارة ، محاطة باقواس [] وفي حالة لم تيم اختيار شيء معنا * ،
الخطوة القادمة هي تجميع عناصر هذه القائمة في قيمة نصية واحدة مفصول بينهم ب ,
لفعل ذلك نستخدم الدالة Aggregate التي وظيفتها تجميع عناصر القائمة في قيمة واحدة ، تأخد مدخل تعبير لمدا ذو مدخلين ومخرج واحد
يطلب منك اذا كان لديك هذين العنصرين (x,y) مثلا كيف تقوم بتجميعهم ؟
نخبره اننا نريده ان يضع القيمة الاولى متبوعة بفاصلة متبوعة بالقيمة الثانية
حسنا الان انتهينا من المطلوب للمتغير selects ، الان وقت مناسب جدا لاخذ كوب ساخن من الشاي الثقيل عديم السكر
انتهيت ؟ مرحبا بك مجددا
بقي لنا ان نحصل على قيمة المتغير wheres
نبدأ مثلما بدأنا سابقا ، نحول العناصر باستخدام Cast :
نختار الصفوف المحددة فقط في الخلايا الثالثة ( CheckBox الخاص ب Where )
بعد ذلك نحصل على قيم الصفوف المطلوب عمل شرط بها وكذلك احاطتها باقواس [] واضافة قيمة الشرط لها ='value'
الكود التالي نخبره ان يحول كل عنصر من القائمة الى ما نريده :
لاحظ ان x.Cells(0).Value تمثل اسم العمود بينما x.Cells(3).Value تمثل قيمة الشرط بعد Where=
نجعل القيمة الافتراضية 1=1 ، في حالة ليس هناك عناصر شرط نريد جلب الكل في الاستعلام :
واخيرا تجميع العناصر والفصل بينهم ب AND
اخر خطوة هي وضع العناصر في متغير الاستعلام :
وبعد ذلك اخراجها للمستخدم :
حسنا انتهينا فعلا ،
النتيجة :
مع عدم اختيار اي شيء :
اتمنى اكون قد وفقني الله لتبسيط المعلومة ، انا جاهز للاسئلة بخصوص هذا الموضوع
اتمنى ان ينتشر استخدام LINQ بين الاخوة العرب
السلام عليكم ورحمة الله وبركاته اعضاء المنتدى الكرام
الموضوع بلغة C#
لايخفى عليكم اخواني الكرام اهمية وقوة تقنية LINQ ، فهذه التقنية جعلت التعامل مع البيانات اسهل بكثير جدا ، فما كان يتطلب عديد السطور لانجازة اصبح الان يكفي سطر واحد لعمله
تقديم :
تقنيه LINQ ليست فقط لقواعد البيانات ، في الحقيقة هذه التقنيه تتعامل مع اي فئة تتضمن الواجهة IEnumerable اي قابلة للعد ، وهذا يشمل المصفوفات Arrays و القوائم generic lists
تتضمن هذه الواجهة طرق كثيرة جدا للتعامل مع البيانات ، مثل Select , Where , Aggregate وغيرها الكثير والكثير
لذلك فكرت انه من باب التطبيق نقوم بعمل مثال يقوم بانشاء استعلام SQL بناء على بيانات الجدول المختارة من المستخدم ، او ما يصطلح الاخوة على تسميته "صانع اكواد"
ويجب قبل البدأ ان اخبركم ان الهدف من هذا المثال هو التدرب على استخدام LINQ وليس هو شرح كيفية عمل برنامج صانع اكواد ، فهذا موضوع قد قتل بحثا من جانب الاخوة الكرام
ولاجل الوصول الى ذلك بابسط طريقة ممكنة هناك بعض المفاهيم التي يجب ان نتفق عليها اولا :
مفاهيم اساسية خارج LINQ :
- string interpolation الادخال وسط النصوص :
تتيح لنا هذه الميزة ادخال القيم وسط النصوص بطريقة سهلة جدا واكثر امانا ،
مثلا اذا كان لدينا متغير اسمه i نريد ان ندخله وسط قيمة نصية فان المطلوب هو ان تسبق القيمة النصية ب العلامة $ وان تضع المتغير داخل قوسين {} :
كود :
Dim str As String = $"I'm {i} years old"
المطلوب :
قيمة من نوع String تمثل نص الاستعلام بالشكل التالي حسب الصفوف المختارة :
PHP كود :
SELECT [Col1],[Col2],[Col3] FROM [Table] WHERE [Col1]='Value' AND [Col2]='Value'
البداية :
نبدأ بتصميم بسيط يؤدي الغرض :
لاحظ الداتا جريد فيو قمنا باضافة 4 اعمدة لها عبارة عن :
- اسماء الاعمدة ،
- هل هذا العمود داخل في جملة SELECT ،
- هل هذا العمود داخل في قيمة WHERE ،
- اذا كان داخل في جملة WHERE ما القيمة المطلوبة للشرط
دعونا اولا نفكر فيما سنحتاجه ،
صيغة الاستعلام التي نريدها تتكون من كلمات ثابتة : "SELECT" و "FROM" و "WHERE"
وكلمات مغيرة : اسماء الحقول المختارة بعد SELECT وكذلك الشروط الموضوعة بعد WHERE وكذلك اسم الجدول
طيب لذلك سنقوم بتعريف 4 متغيرات من نوع String
- tableName : وهو يمثل اسم الجدول المطلوب انشاء قيمة استعلام له
- selects : الحقول المطلوبة محاطة ب [] و مفصول بينها ب ,
- wheres : حقول الشروط محاطة ب [] ايضا ومتبوعة بالقيمة على شكل ='value' و كذلك مفصول بينها ب AND
- sqlCommand : نخزن فيه الاستعلام المنشأ
هيا بنا في حدث btnGenerateSql.Click نعرف متغير اسم الجدول ونسند له قيمة من مربع النص الخاص باسم الجدول محاط بالاقواس [] :
كود :
Dim tableName As String = $"[{txtTableName.Text}]"
كيف نحصل على القيمة المطلوبة للمتغير selects ؟
طيب نبدأ العمل الحقيقي الان ، نريد الحصول على صفوف الداتا جريد فيو على شكل IEnumerable من نوع DataGridViewRow لنتمكن من استخدام طرق LINQ عليها ،
لفعل ذلك نستخدم الطريقة Cast ونمرر لها النوع DataGridViewRow :
كود :
Dim selects = dgvTable.Rows.
Cast(Of DataGridViewRow)()
جميل جدا ، الان ركزو معي جيدا ، نريد اختيار الصفوف المختارة فقط كجزء من Select ، اي الصفوف التي فيها قيمة الخلية الثانية ب True ،
لفعل ذلك نحن بحاجة الى الطريقة Where ، التي هي دالة الاختيار ، وظيفتها انها تختار من عناصر بيانات العناصر التي توافق شرط معين ، تقبل مدخل تعبير لمدا يمثل الشرط الذي يتم الاخيار بناء عليه ، وهو في هذه الحالة قيمة الخلية الثانية من الصف الحالي x.Cells(1).Value
كود :
Dim selects = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(1).Value)
الان حصلنا على الصفوف المطلوبة فقط ، جميل جدا نريد الان الحصول منها على اسماء الاعمدة المطلوبة ( قيمة الخلية الاولى في الصف ) محاطة ب [] ،
لفعل ذلك نستخدم الدالة Select التي تسمي دالة التحويل ، وظيفتها انها تحول كل العناصر التي تطبق عليها الى صورة اخرى ، في حالتنا نريد تحويل عناصر صفوف الداتا جريد فيو DataGridViewRow الى قيم نصية String تمثل اسماء الاعمدة ، الدالة تقبل مدخل تعبير لمدا يمثل التحويل المطلوب على كل عنصر ، وهو في هذه الحالة قيمة الخلية الاولى محاطة باقواس $"[{x.Cells(0).Value}]"
كود :
Dim selects = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(1).Value).
Select(Function(x) $"[{x.Cells(0).Value}]")
طيب جميل جدا الان ماذا اذا لم يختار المستخدم اي صف ؟ في هذه الحالة تكون القائمة فارغة ، نريد في هذه الحالة ان تكون القيمة الافتراضية "*" هي العنصر الوحيد ، يعني في حالة لم يتم اختيار صف معين نحن سنعيد القيمة * التي تعني كل الاعمدة في SQL ،
لفعل ذلك نستخدم الدالة DefaultIfEmpty التي وظيفتها انها ترجع بعنصر وحيد عبارة عن القيمة الافتراضية التي تمررها لها في حالة كانت القائمة التي تطبق عليها فارغة ، في هذه الحالة نمرر لها القيمة "*"
كود :
Dim selects = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(1).Value).
Select(Function(x) $"[{x.Cells(0).Value}]").
DefaultIfEmpty("*")
طيب الان جميل جدا جدا جدا ، معنا قائمة فيها كل اسماء الاعمدة المختارة ، محاطة باقواس [] وفي حالة لم تيم اختيار شيء معنا * ،
الخطوة القادمة هي تجميع عناصر هذه القائمة في قيمة نصية واحدة مفصول بينهم ب ,
لفعل ذلك نستخدم الدالة Aggregate التي وظيفتها تجميع عناصر القائمة في قيمة واحدة ، تأخد مدخل تعبير لمدا ذو مدخلين ومخرج واحد
يطلب منك اذا كان لديك هذين العنصرين (x,y) مثلا كيف تقوم بتجميعهم ؟
نخبره اننا نريده ان يضع القيمة الاولى متبوعة بفاصلة متبوعة بالقيمة الثانية
كود :
Function(x, y) $"{x},{y}"
كود :
Dim selects = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(1).Value).
Select(Function(x) $"[{x.Cells(0).Value}]").
DefaultIfEmpty("*").
Aggregate(Function(x, y) $"{x},{y}")
حسنا الان انتهينا من المطلوب للمتغير selects ، الان وقت مناسب جدا لاخذ كوب ساخن من الشاي الثقيل عديم السكر
انتهيت ؟ مرحبا بك مجددا
بقي لنا ان نحصل على قيمة المتغير wheres
نبدأ مثلما بدأنا سابقا ، نحول العناصر باستخدام Cast :
كود :
Dim wheres = dgvTable.Rows.
Cast(Of DataGridViewRow)()
نختار الصفوف المحددة فقط في الخلايا الثالثة ( CheckBox الخاص ب Where )
كود :
Dim wheres = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(2).Value)
بعد ذلك نحصل على قيم الصفوف المطلوب عمل شرط بها وكذلك احاطتها باقواس [] واضافة قيمة الشرط لها ='value'
الكود التالي نخبره ان يحول كل عنصر من القائمة الى ما نريده :
كود :
Dim wheres = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(2).Value).
Select(Function(x) $"[{x.Cells(0).Value}]='{x.Cells(3).Value}'")
لاحظ ان x.Cells(0).Value تمثل اسم العمود بينما x.Cells(3).Value تمثل قيمة الشرط بعد Where=
نجعل القيمة الافتراضية 1=1 ، في حالة ليس هناك عناصر شرط نريد جلب الكل في الاستعلام :
كود :
Dim wheres = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(2).Value).
Select(Function(x) $"[{x.Cells(0).Value}]='{x.Cells(3).Value}'").
DefaultIfEmpty("1=1")
واخيرا تجميع العناصر والفصل بينهم ب AND
كود :
Dim wheres = dgvTable.Rows.
Cast(Of DataGridViewRow)().
Where(Function(x) x.Cells(2).Value).
Select(Function(x) $"[{x.Cells(0).Value}]='{x.Cells(3).Value}'").
DefaultIfEmpty("1=1").
Aggregate(Function(x, y) $"{x} AND {y}")
اخر خطوة هي وضع العناصر في متغير الاستعلام :
كود :
Dim sqlCommand As String = $"SELECT {selects} FROM {tableName} WHERE {wheres}"
وبعد ذلك اخراجها للمستخدم :
كود :
txtSql.Text = sqlCommand
حسنا انتهينا فعلا ،
النتيجة :
مع عدم اختيار اي شيء :
اتمنى اكون قد وفقني الله لتبسيط المعلومة ، انا جاهز للاسئلة بخصوص هذا الموضوع
اتمنى ان ينتشر استخدام LINQ بين الاخوة العرب