آموزش IEnumerable و IQueryable در C#

IQueryable

در این مقاله به بررسی IEnumerable و IQueryable در سی شارپ پرداختیم ویژگی هر یک و چه زمانی باید از IEnumerable و IQueryable استفاده کنیم.ما در این مقاله نیز به بررسی با موضوع چه زمانی از IEnumerable ، ICollection، IList و List استفاده کنیم؟  دیگر ویژگی ها را بررسی کردیم.

یک برنامه نویس C# همیشه در استفاده از رابط های زیر دچار سردرگمی می شود:

  • IEnumerable
  • IQueryable
  • ICollection
  • IList

با توجه به اینکه سردرگمی برنامه نویسان در استفاده از رابط های بالا را مشاهده کردم تصمیم دارم در این مقاله، تفاوت های اصلی بین IEnumerable<T> و IQueryable<T> و همین طور موارد استفاده هرکدام را توضیح دهم.

IEnumerable<T>

IEnumerable<T>  برای حلقه تکرار زدن روی یک مجموعه فقط خواندنی است (read only collection)، که تنها یک متد GetEnumeartor()  دارد که این امکان را فراهم می کند با استفاده از حلقه ی foreach مجموعه های read only collection را تکرارکند. تکرار فقط در جهت جلو امکان پذیر است. IEnumerable <T> به صورت زیر تعریف می شود:

IQueryable

همان طور که مشاهده می کنید این تعریف شامل هیچ تابع دیگری مثل add,remove,count و غیره نیست. پس نمی توانید اشیا را در IEnumerable collection جمع یا حذف کنید بلکه فقط یک مجموعه فقط خواندنی است و حتی برای پیدا کردن شماره هر شی در مجموعه، باید روی کل مجموعه عمل حلقه تکرار بزنید. از مهم ترین نکات مربوط به IEnumerable<T> در ادامه مطرح خواهد شد:

  • یک مجوعه فقط خواندنی است
  • تکرار فقط در جهت جلو(مستقیم) صورت می گیرد.
  • اعمال جمع یا حذف روی objects امکان پذیر نیست.
  • برای تکرار در مجموعه (در جهت مستقیم)، enumerator فراهم شده است.

یک رابط پایه است برای هرنوع مجموعه ای که با استفاده از دستور foreach قابل شمارش(enumerate) است. برای انجام عمل تکرار از یک foreach استفاده می کنیم و یک مجموعه عمومی باید  IEnumerable <T>  را پیاده سازی کرده و متد GetEnumerator() را تعریف کند.

IQueryable

متد GetEnumerator() ریسمان(thread) امنی نیست. Enumerator برای خواندن مجموعه ها از موقعیت یابی استفاده کرده و در اولین موقعیت در یک مجموعه قرار می گیرد. برای خواندن اشیا بعدی در مجموعه . باید متد MoveNext() را فراخوانی کنید.

چه زمانی از IEnumerable<T>  استفاده کنیم؟

به سوالات زیر پاسخ دهید:

آیا می خواهید با مجموعه های read only collection کار کنید؟

آیا نیاز به خواندن Objects(در جهت فقط پیشرو) دارید؟

نسبت به امنیت ریسمان ها نگران نیستید؟

آیا می خواهید با استفاده از foreach روی مجموعه های اشیا عمل تکرار را انجام دهید؟

اگر تنها به یکی از سوال های بالا پاسخ مثبت دادید پس به نحوه استفاده از IEnumerable <T> در ادامه توجه کنید:

IQueryable<T>

طبق مستندات MSDN ، IQueryable<T>  اجازه می دهد تا روی یک منبع داده ای مشخص،که نوع داده های آن مشخص نیست، یک پرس و جو اجرا کنید.

IQueryable به صورت زیر تعریف می شود:

IQueryable

IQueryable<T> ،IEnumerable را توسعه داده و در نتیجه به شما اجازه می دهد تا عمل تکرار روی یک مجموعه را با استفاده از دستور foreach  انجام دهید. تمامی مشخصات یک IQueryable فقط خواندنی است.

IQueryable<T>  ، IQueryable و IEnumerable را توسعه داده و به صورت زیر تعریف می شود:

IQueryable

برای واکشی یک رکورد از یک پایگاه داده( از راه دور) باید از IQueryable<T>  استفاده کنید. IQueryable پرس و جو را با استفاده از درخت عبارت ها(Expression Tree) شکل می دهد. به عبارت دیگر در IEnumerable <T> پرس و جو با استفاده از delegate ایجاد می شود. با استفاده از IQueryable<T>  و IEnumerable <T> به راحتی می توان از سرور های پایگاه داده، داده ها را بارگذاری کرد.

وقت آن رسیده تا از IEnumerable <T> یا IQueryable<T>  استفاده کنیم اجازه دهید تا SQL تولید شده برای LINQ زیر را به نمایش بگذاریم:


DataClasses1DataContext context = new DataClasses1DataContext();

IEnumerable<Order> result = context.Orders;

var product = result.Where(x => x.OrderID == 10248);

context.Log = Console.Out;

foreach(var r in product)

{


Console.WriteLine(r.ShipName);

}

SQL تولید شده به صورت زیر خواهد بود:

IQueryable

همان طور که دقت می کنید اگرچه با استفاده از عملگر where روی پرس و جویمان، فیلتر اعمال کردیم، IEnumerable<T> همه ی داده ها را از جدول پایگاه داده مان واکشی کرده و فیلتر را روی تمامی داده های بازگشتی در حافظه، اعمال کرده است.

به عبارت بهتر، اجازه دهید تا پرس و جوی قبلی را با استفاده از IQueryable<T>  بازنویسی کنیم و پرس و جوی SQL تولید شده را امتحان کنیم:

C#


IQueryable<Order> result1 = context.Orders;

var product1 = result1.Where(x => x.OrderID == 10248);

context.Log = Console.Out;

foreach (var r in product1)

{

Console.WriteLine(r.ShipName);

}


Console.ReadKey(true);

SQL تولید شده به صورت زیر خواهد بود:

IQueryable

همانطور که متوجه هستید، پرس و جوی تولید شده یک عبارت where داشته و به وسیله ی  LINQ to SQL، تنها داده های فیلتر شده از پایگاه داده واکشی می شوند. اگر از IQueryable و foreach استفاده می کنید، پرس و جو در زمان یکسانی محاسبه و اجرا می شود.

حالا نوبت به بررسی مهم ترین نکات مربوط به IQueryable<T> است:

  • IEnumerable <T> را پیاده سازی می کند پس با استفاده از foreach می توان روی نتایج عمل تکرار را انجام دهیم.
  • بهترین روش برای پرس و جو زدن در منابع داده ای خارجی هستند(external data sources).
  • با استفاده از درخت عبارت ها، پرس و جو را ایجاد می کند.
  • برای پرس و جو زدن روی منابع داده ای قابل پرس و جو(queryable) استفاده می شوند.

وقتی از IQueryable<T> استفاده می کنید پرس و جو با استفاده از درخت عبارت ایجاد می شود و یک قدم جلوتر از سرویس دهنده LINQ برداشته و درخت عبارت را به پرس و جو واقعی تبدیل می کند. همیشه به خاطر داشته باشید که IQueryable<T> فقط پرس و جو را ساخته و داده ها را از روش غیر مستقیم بارگذاری می کند.

چه زمانی از IQueryable<T> استفاده کنیم؟

به سوالات زیر پاسخ دهید:

  • آیا می خواهید با با منابع داده ای قابل پرس و جو زدن، کار کنید؟
  • آیا می خواهید روی داده های موجود در منابع تان فیلتر اعمال کنید؟
  • می خواهید صفحه بندی(paging) و ترکیب(composition) انجام دهید؟
  • با منابع داده ای خارجی کار می کنید؟
  • می خواهید داده ها را به روش غیر مستقیم بارگذاری کنید؟
  • می خواهید با استفاد از foreach روی مجموعه عمل تکرار را انجام دهید؟

اگر تنها به یکی از سوال های بالا پاسخ مثبت دادید پس به نحوه استفاده از IQueryable<T> در ادامه توجه کنید:

هنگام استفاده از مواظب باشید IQueryable کپسول سازی(encapsulation) مخزن تان(repository) از بین نرود، نگرانید که برخی داده های مشخص از مخزنتان برای بقیه کدهایتان آشکار باشد.

اگر واقعا می خواهید از یک مخزن استفاده کنید البته با اعمال فیلتر؛ باید موارد زیر را رعایت کنید:

اضافه کردن متدهای پرس و جوی اضافی یا فرستادن یک مشخصه یا یک گزاره(خبر) به یکی از متدهای لیست مخازن(همچنان IEnumerable را برمی گرداند)

خلاصه:

IEnumerable <T> با مجموعه های در حافظه محلی کار می کنند برخلاف IQueryable<T>  که با پایگاه دادهکار می کند. اگر با  LINQ to SQL کار می کنید بهترین راه استفاده از IEnumerable <T> است البته تا زمانی که خبری از live data نباشد یا بخواهید از کلاس DataConext توابع فراخوانی(call functions) را حذف یا اضافه کنید.

IQueryable<T> لیستی از خودش را بر نمی گرداند و ترجیحا پرس و جو را خودش می سازد. برای برگرداندن لیست از IQueryable<T> باید از AsQueryable استفاده کنید.

  • پسورد: www.mspsoft.com
محمد دهقانی

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

    حسن وادیپور پاسخ

    مباحث خوبی را مورد بررسی قرار میدهد و بنده از سایت بسیار لذت میبرم