07-09-20, 02:29 AM
(آخر تعديل لهذه المشاركة : 07-09-20, 10:14 AM {2} بواسطة Anas Mahmoud.)
بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته اعضاء المنتدى الكرام
الموضوع بلغة VB
لايخفى عليكم اخواني الكرام اهمية وقوة تقنية 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
ولكن اذا كان الخلية لم يتم الضغط عليها قيمتها تكون null ويرمي البرنامج ب خطأ ، لذلك نستخدم المعاملين ? و ?? لتلافي ذلك :
الان حصلنا على الصفوف المطلوبة فقط ، جميل جدا نريد الان الحصول منها على اسماء الاعمدة المطلوبة ( قيمة الخلية الاولى في الصف ) محاطة ب [] ،
لفعل ذلك نستخدم الدالة 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 بين الاخوة العرب
السلام عليكم ورحمة الله وبركاته اعضاء المنتدى الكرام
الموضوع بلغة VB
لايخفى عليكم اخواني الكرام اهمية وقوة تقنية LINQ ، فهذه التقنية جعلت التعامل مع البيانات اسهل بكثير جدا ، فما كان يتطلب عديد السطور لانجازة اصبح الان يكفي سطر واحد لعمله
تقديم :
تقنيه LINQ ليست فقط لقواعد البيانات ، في الحقيقة هذه التقنيه تتعامل مع اي فئة تتضمن الواجهة IEnumerable اي قابلة للعد ، وهذا يشمل المصفوفات Arrays و القوائم generic lists
تتضمن هذه الواجهة طرق كثيرة جدا للتعامل مع البيانات ، مثل Select , Where , Aggregate وغيرها الكثير والكثير
لذلك فكرت انه من باب التطبيق نقوم بعمل مثال يقوم بانشاء استعلام SQL بناء على بيانات الجدول المختارة من المستخدم ، او ما يصطلح الاخوة على تسميته "صانع اكواد"
ويجب قبل البدأ ان اخبركم ان الهدف من هذا المثال هو التدرب على استخدام LINQ وليس هو شرح كيفية عمل برنامج صانع اكواد ، فهذا موضوع قد قتل بحثا من جانب الاخوة الكرام
ولاجل الوصول الى ذلك بابسط طريقة ممكنة هناك بعض المفاهيم التي يجب ان نتفق عليها اولا :
مفاهيم اساسية خارج LINQ :
- string interpolation الادخال وسط النصوص :
تتيح لنا هذه الميزة ادخال القيم وسط النصوص بطريقة سهلة جدا واكثر امانا ،
مثلا اذا كان لدينا متغير اسمه i نريد ان ندخله وسط قيمة نصية فان المطلوب هو ان تسبق القيمة النصية ب العلامة $ وان تضع المتغير داخل قوسين {} :
string str = $"I'm {i} years old"; - null-coalescing operator :
عندما تحاول قراءة قيمة متغير ما قيمته null فانك ستحصل على Exception بسبب ذلك ، طيب ماذا اذا كنت تريد ان تضع قيمة افتراضية عندما يكون المتغير ب null ترجع هذه القيمة بدلا من ان يحدث Exception ، هنا يأتي دور المعامل ? والمعامل ??
المعامل ? يستخدم قبل نوع المتغير ويعني بان هذا المتغير يقبل القيم null
المعامل ?? يوضع بعد قراءة المتغير ويوضع بعده القيمة الافتراضية اذا كان المتغير ب null
السطر التالي سيضع القيمة 0 في number اذا كان i ب null بدلا من ان يرمي ب خطأ
كود :
int number = (int?)i ?? 0;
المطلوب :
قيمة من نوع 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 نعرف متغير اسم الجدول ونسند له قيمة من مربع النص الخاص باسم الجدول محاط بالاقواس [] :
كود :
string tableName = $"[{txtTableName.Text}]";
كيف نحصل على القيمة المطلوبة للمتغير selects ؟
طيب نبدأ العمل الحقيقي الان ، نريد الحصول على صفوف الداتا جريد فيو على شكل IEnumerable من نوع DataGridViewRow لنتمكن من استخدام طرق LINQ عليها ،
لفعل ذلك نستخدم الطريقة Cast ونمرر لها النوع DataGridViewRow :
كود :
var selects = dgvTable.Rows
.Cast<DataGridViewRow>();
جميل جدا ، الان ركزو معي جيدا ، نريد اختيار الصفوف المختارة فقط كجزء من Select ، اي الصفوف التي فيها قيمة الخلية الثانية ب True ،
لفعل ذلك نحن بحاجة الى الطريقة Where ، التي هي دالة الاختيار ، وظيفتها انها تختار من عناصر بيانات العناصر التي توافق شرط معين ، تقبل مدخل تعبير لمدا يمثل الشرط الذي يتم الاخيار بناء عليه ، وهو في هذه الحالة قيمة الخلية الثانية من الصف الحالي x.Cells[1].Value
كود :
var selects = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool)x.Cells[1].Value);
ولكن اذا كان الخلية لم يتم الضغط عليها قيمتها تكون null ويرمي البرنامج ب خطأ ، لذلك نستخدم المعاملين ? و ?? لتلافي ذلك :
كود :
var selects = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[1].Value ?? false);
الان حصلنا على الصفوف المطلوبة فقط ، جميل جدا نريد الان الحصول منها على اسماء الاعمدة المطلوبة ( قيمة الخلية الاولى في الصف ) محاطة ب [] ،
لفعل ذلك نستخدم الدالة Select التي تسمي دالة التحويل ، وظيفتها انها تحول كل العناصر التي تطبق عليها الى صورة اخرى ، في حالتنا نريد تحويل عناصر صفوف الداتا جريد فيو DataGridViewRow الى قيم نصية String تمثل اسماء الاعمدة ، الدالة تقبل مدخل تعبير لمدا يمثل التحويل المطلوب على كل عنصر ، وهو في هذه الحالة قيمة الخلية الاولى محاطة باقواس $"[{x.Cells[0].Value}]"
كود :
var selects = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[1].Value ?? false)
.Select(x => $"[{x.Cells[0].Value}]");
طيب جميل جدا الان ماذا اذا لم يختار المستخدم اي صف ؟ في هذه الحالة تكون القائمة فارغة ، نريد في هذه الحالة ان تكون القيمة الافتراضية "*" هي العنصر الوحيد ، يعني في حالة لم يتم اختيار صف معين نحن سنعيد القيمة * التي تعني كل الاعمدة في SQL ،
لفعل ذلك نستخدم الدالة DefaultIfEmpty التي وظيفتها انها ترجع بعنصر وحيد عبارة عن القيمة الافتراضية التي تمررها لها في حالة كانت القائمة التي تطبق عليها فارغة ، في هذه الحالة نمرر لها القيمة "*"
كود :
var selects = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[1].Value ?? false)
.Select(x => $"[{x.Cells[0].Value}]")
.DefaultIfEmpty("*");
طيب الان جميل جدا جدا جدا ، معنا قائمة فيها كل اسماء الاعمدة المختارة ، محاطة باقواس [] وفي حالة لم تيم اختيار شيء معنا * ،
الخطوة القادمة هي تجميع عناصر هذه القائمة في قيمة نصية واحدة مفصول بينهم ب ,
لفعل ذلك نستخدم الدالة Aggregate التي وظيفتها تجميع عناصر القائمة في قيمة واحدة ، تأخد مدخل تعبير لمدا ذو مدخلين ومخرج واحد
يطلب منك اذا كان لديك هذين العنصرين (x,y) مثلا كيف تقوم بتجميعهم ؟
نخبره اننا نريده ان يضع القيمة الاولى متبوعة بفاصلة متبوعة بالقيمة الثانية
كود :
(x, y) => $"{x},{y}"
كود :
var selects = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[1].Value ?? false)
.Select(x => $"[{x.Cells[0].Value}]")
.DefaultIfEmpty("*")
.Aggregate((x, y) => $"{x},{y}" );
حسنا الان انتهينا من المطلوب للمتغير selects ، الان وقت مناسب جدا لاخذ كوب ساخن من الشاي الثقيل عديم السكر
انتهيت ؟ مرحبا بك مجددا
بقي لنا ان نحصل على قيمة المتغير wheres
نبدأ مثلما بدأنا سابقا ، نحول العناصر باستخدام Cast :
كود :
var wheres = dgvTable.Rows
.Cast<DataGridViewRow>();
نختار الصفوف المحددة فقط في الخلايا الثالثة ( CheckBox الخاص ب Where )
كود :
var wheres = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[2].Value ?? false);
بعد ذلك نحصل على قيم الصفوف المطلوب عمل شرط بها وكذلك احاطتها باقواس [] واضافة قيمة الشرط لها ='value'
الكود التالي نخبره ان يحول كل عنصر من القائمة الى ما نريده :
كود :
var wheres = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[2].Value ?? false)
.Select(x => $"[{x.Cells[0].Value}]='{x.Cells[3].Value}'");
لاحظ ان x.Cells[0].Value تمثل اسم العمود بينما x.Cells[3].Value تمثل قيمة الشرط بعد Where=
نجعل القيمة الافتراضية 1=1 ، في حالة ليس هناك عناصر شرط نريد جلب الكل في الاستعلام :
كود :
var wheres = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[2].Value ?? false)
.Select(x => $"[{x.Cells[0].Value}]='{x.Cells[3].Value}'")
.DefaultIfEmpty("1=1");
واخيرا تجميع العناصر والفصل بينهم ب AND
كود :
var wheres = dgvTable.Rows
.Cast<DataGridViewRow>()
.Where(x => (bool?)x.Cells[2].Value ?? false)
.Select(x => $"[{x.Cells[0].Value}]='{x.Cells[3].Value}'")
.DefaultIfEmpty("1=1")
.Aggregate((x, y) => $"{x} AND {y}");
اخر خطوة هي وضع العناصر في متغير الاستعلام :
كود :
string sqlCommand = $"SELECT {selects} FROM {tableName} WHERE {wheres}";
وبعد ذلك اخراجها للمستخدم :
كود :
txtSql.Text = sqlCommand;
حسنا انتهينا فعلا ،
النتيجة :
مع عدم اختيار اي شيء :
اتمنى اكون قد وفقني الله لتبسيط المعلومة ، انا جاهز للاسئلة بخصوص هذا الموضوع
اتمنى ان ينتشر استخدام LINQ بين الاخوة العرب