الفرق بين IEnumerable وIQueryable في لغة البرمجة #C
- مقدمة
- ما هو IEnumerable
- ما هو IQueryable
- الفرق بين IEnumerable و IQueryable
مقدمة
في لغة البرمجة #C يعتبر الإنترفيس IEnumerable و IQueryable جزءاً أساسياً من LINQ و تستخدمان بشكل واسع للاستعلام و معالجة البيانات و بالطبع فهم الفروق بينهما و كيفية استخدام كل منهما بشكل صحيح أمراً هاماً في الاستعلام عن البيانات.
ما هو IEnumerable
الإنترفيس IEnumerable يوفر طريقة بسيطة و قوية لجلب مجموعات البيانات و يسمح بتنفيذ العمليات الأساسية عليها، مثل تنفيذ الاستعلامات و معالجة البيانات كعمليات الفلترة و الترتيب، و يستخدم بشكل رئيسي مع مجموعات البيانات الموجودة في الذاكرة، مثل القوائم (List) و المصفوفات (Array).
يستخدم الإنترفيس IEnumerable في الاستعلام عن الكائنات (LINQ to Objects) هذا يعني أنه يتم استخدامه للاستعلام عن البيانات الموجودة في الذاكرة مثل القوائم و المصفوفات و غيرها من مجموعات البيانات التي يتم تحميلها في الذاكرة. و هو يتعامل بشكل مباشر مع المجموعات البيانات داخل الذاكرة و عندما يتم إجراء استعلام باستخدام IEnumerable فإنه يتم تنفيذ الاستعلام على الفور و يتم إرجاع النتائج كعناصر منفصلة من الذاكرة بمعنى أن كل عملية تكرار (Iteration) على المجموعة تتم مباشرة على العناصر الموجودة داخل الذاكرة.
مثال
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 }; IEnumerable<int> query = numbers.Where(x => x > 2); foreach (var item in query){ Console.WriteLine(item); }
ما هو IQueryable
يوفر الإنترفيس IQueryable وظائف استعلام أكثر تقدماً، حيث يستخدم للتعامل مع بيانات من مصادر خارجية مثل قواعد البيانات و غيرها و يسمح ببناء استعلامات LINQ قوية و تأجيل تنفيذها حتى وقت طلب البيانات، مما يسمح بتحسين أداء التطبيقات و استخدام الموارد بشكل أفضل.
يستخدم الإنترفيس IQueryable في الإستعلام LINQ to Out-of-process مما يعني أنه يتم استخدامه للاستعلام عن البيانات التي قد تكون موجودة خارج الذاكرة، مثل قواعد البيانات أو خدمات الويب، و الاستعلامات التي تُكتب باستخدام IQueryable يمكن ترجمتها إلى استعلامات بلغة أخرى مثل SQL.
تحويل الكود إلى Expression Trees
يستخدم IQueryable بنية البيانات المسماة Expression Trees لتمثيل الاستعلام ككود يمكن تحليله و تفسيره بدلاً من تنفيذ الاستعلام مباشرة، حيث يتم تحويل الاستعلام إلى expression trees، و بعد تحويله يتم تمريره إلى LINQ الوسيط، الذي يكون مسؤولاً عن ترجمة Expression Trees إلى إستعلام مناسب للبيانات المصدرية، مثل قواعد بيانات SQL.
ترجمة الاستعلام
تقوم تقنية LINQ الوسيط بترجمة Expression Trees إلى الإستعلام المناسب لمصدر البيانات، مما يسمح بتنفيذ الاستعلام بكفاءة في مصدر البيانات الخارجي، حيث يمكن تحسينه بناءاً على قدرات نظام إدارة قاعدة البيانات أو الخدمة التي تستضيف البيانات.
مثال
// "Electronics" الإستعلام الأول يقوم بجلب منتجات من فئة IQueryable<Product> productsQuery = dbContext.Products.Where(p => p.Category == "Electronics"); // الإستعلام الثاني يقوم بجلب منتجات سعرها أقل من 100 دولار IQueryable<Product> cheapProducts = productsQuery.Where(p => p.Price < 100); // الإستعلامات السابقة سيتم تنفيذها عندما يتم طلب البيانات في الحلقة التالية foreach (var product in cheapProducts) { Console.WriteLine($"{product.Name} - {product.Price}"); }
توضيح فكرة تأجيل التنفيذ و التحويل إلى Expression Trees
- تأجيل التنفيذ - عند تعريف
productsQuery
وcheapProducts
لا يتم تنفيذ أي استعلام على الفور بل يتم بناء Expression Tree بشكل مباشر لتمثل الاستعلامات بشكل مجرد قبل أن يتم تنفيذها فعلياً. - تحويل الاستعلامات إلى Expression Tree - عملية تحويل الاستعلامات إلى Expression Tree تحدث أثناء تنفيذ الأسلوب
Where
حيث يتم بناء Expression Tree تمثل الشروط المحددة في الإستعلام، مثل التحقق من فئة المنتج و سعره. - تنفيذ الاستعلامات - عندما يتم استخدام
cheapProducts
في الحلقةforeach
، يتم تنفيذ الاستعلامات و يتم تحويل Expression Tree إلى إستعلام SQL مناسب باستخدام LINQ الوسيط (Intermediate LINQ Provider). الإستعلام الناتج يتم تنفيذه خارج قاعدة البيانات، بمعنى آخر، يتم استعلام مصادر بيانات خارجية مثل APIs أو خدمات الويب بدلاً من قاعدة البيانات المحلية. و النتائج تعود بشكل فعلي و تُستخدم في الحلقة لطباعة تفاصيل المنتجات.
الفرق بين IEnumerable و IQueryable
IQueryable | IEnumerable | |
---|---|---|
نوع البيانات | يمكنه العمل مع البيانات الموجودة خارج الذاكرة، مثل قواعد البيانات. | يعمل مع البيانات الموجودة في الذاكرة فقط. |
مكان تنفيذ الاستعلام | يتم تأجيل تنفيذ الاستعلام حتى يتطلب ذلك بشكل صريح، مما يسمح بترجمة الاستعلام إلى لغة مناسبة لمصدر البيانات. | يتم تنفيذ الاستعلام فوراً عند التكرار على مجموعة البيانات. |
الأداء | أفضل مع المجموعات الكبيرة أو البيانات الموجودة خارج الذاكرة، حيث يمكن تحسين الاستعلام قبل تنفيذه. | جيد مع المجموعات الصغيرة الموجودة في الذاكرة. |
في النهاية يتم استخدام كل من IEnumerable و IQueryable حسب متطلبات المشروع حيث يمكن أن يكون استخدام IEnumerable مناسب عندما تكون البيانات داخل الذاكرة و الاستعلامات بسيطة، بينما يكون IQueryable مناسباً للإستعلامات المعقدة على البيانات الكبيرة أو البعيدة حيث يمكن تحسين الأداء بشكل كبير و الاختيار بينهما يعتمد على حالة كل مشروع و متطلباته كما ذكرنا سابقاَ، حيث يمكن استخدام IEnumerable للتعامل مع البيانات بشكل عام، و IQueryable للإستعلامات المعقدة التي تحتاج إلى تحسين الأداء.