کلمهی LINQ مخفف Language Integrated Query یا زبان پرس و جوی یکپارچه میباشد. LINQ برای اولین بار در ویژوال استودیوی 2008 و دات نت فریم ورک 3.5 برای پرکردن خلع بین دنیای اشیاء برنامه نویسی (Object Oriented World) و دنیای دادهها (Data World) ارائه شد.
چرا LINQ؟
در نگاهی کلی، مزایایی که از طریق LINQ حاصل میشوند عبارتند از:
• کاهش حجم کدنویسی
• درک بهتر از عملکرد کدهای نوشته شده
• پس از یادگیری اصول LINQ به راحتی میتوانید از این اصول پرس و جو نویسی برای کار بر روی مجموعه دادههای مختلف استفاده کنید
• کنترل صحت کدهای پرس و جوها در زمان کامپایل ( Compile-Time Type Checking )
اجزای سازندهی LINQ
دو جزء اصلی سازندهی LINQ عبارت است از:
- Elements عناصر
- Sequences توالیها
توالیها میتوانند لیستی از اطلاعات مختلف باشند. هر آیتم در لیست را عنصر میگوییم. توالی نمونهای از یک کلاس است که اینترفیس <IEnumarable<T را پیاده سازی کرده باشد. این اینترفیس تضمین میکند که توالی قابلیت پیمایش عناصر را دارد.
به آرایهی تعریف شدهی زیر دقت کنید:
int[] fibonacci = {0, 1, 1, 2, 3, 5};
متغیر fibonacci در اینجا نشان دهندهی توالی و هر یک از اعداد آرایه، یک عنصر محسوب میشوند.
توالی میتواند درون حافظهای باشد (In Memory Object) که به آن Local Sequence میگویند و یا میتواند یک بانک اطلاعاتی SQL Server باشد که به آن Remote Sequence میگویند.
در حالت Remote باید اینترفیس <IQuerable<T پیاده سازی شده باشد.
پرس و جو هایی را که بر روی توالیهای محلی اجرا میشوند، اصطلاحا Local Query و یا LINQ-To-Object نیز مینامند.
عملگرهای پرس و جوی زیادی به شکل متد الحاقی در کلاس System.Linq.Enumerable طراحی شدهاند. این مجموعه از عملگرهای پرس جو را اصطلاحا Standard Query Operator میگویند.
نکتهی مهم این است که عملگرهای پرس و جو تغییری را در توالی ورودی نمیدهند و نتیجهی خروجی یک مجموعه جدید و یا یک مقدار عددی میباشد.
توالی خروجی و مقدار بازگشتی Scalar
در بخش قبل گفتیم که خروجی یک پرس و جو میتواند یک مجموعه و یا یک مقدار عددی باشد. در مثال زیر عملگر Count را بر روی مجموعهی fibonacci اعمال کردیم و عددی که نشان دهندهی تعداد عناصر مجموعه است، بعنوان خروجی بازگردانده شده است.
int[] fibonacci = { 0, 1, 1, 2, 3, 5 };
int numberOfElements = fibonacci.Count();
Console.WriteLine($"{numberOfElements}");
IEnumerable<int> distinictNumbers = fibonacci.Distinct();
Console.WriteLine("Elements in output sequence:");
foreach (var number in distinictNumbers)
{
Console.WriteLine(number);
}
در کد بالا توسط تابع Distinct، عناصر یکتا را از توالی ورودی استخراج کرده و بازگرداندهایم.
خروجی برنامهی فوق به شکل زیر است :
6
Elements in output sequence:
0
1
2
3
5
عمدهی عملگرهای پرس و جو بلافاصله پس از ایجاد، اجرا نمیشوند. این عملگرها در طول اجرای برنامه اجرا خواهند شد (اجرای با تاخیر). به همین خاطر میتوان بعد از ساخت پرس و جو تغییرات دلخواهی را به توالی ورودی اعمال کرد.
در کد زیر قبل از اجرای پرس و جو ، توالی ورودی ویرایش شده :
int[] fibonacci = { 0, 1, 1, 2, 3, 5 };
// ایجاد پرس و جو
IEnumerable<int> numbersGreaterThanTwoQuery = fibonacci.Where(x => x > 2);
// در این مرحله پرس و جو ایجاد شده ولی هنوز اجرا نشده است
// تغییر عنصر اول توالی
fibonacci[0] = 99;
// حرکت بر روی عناصر توالی باعث اجرای پرس و جو میشود
foreach (var number in numbersGreaterThanTwoQuery)
{
Console.WriteLine(number);
}
پرس و جو تا زمان اجرای حلقهی Foreach اجرا نخواهد شد. خروجی مثال بالا به شکل زیر است :
به غیر از بعضی از عملگرها مثل Count,Min,Last سایر عملگرها بصورت اجرای با تاخیر عمل میکنند. عملگری مثل Count باعث اجرای فوری پرس و جو میشود.
تعدادی عملگر تبدیل (Conversion Operator) هم وجود دارد که باعث میشوند پرس و جو بلافاصله اجرا شود :
• ToList
• ToArray
• ToLookup
• ToDictionary
عملگرهای فوق پس از اجرا، خروجی را در یک ساختمان دادهی جدید باز میگردانند.
در کد زیر اصلاح توالی متغیر Fibonacci بعد از اجرای تابع ToArray صورت گرفته است.
int[] fibonacci = { 0, 1, 1, 2, 3, 5 };
// ساخت پرس و جو
IEnumerable<int> numbersGreaterThanTwoQuery = fibonacci.Where(x => x > 2) .ToArray();
// در این مرحله به خاطر عملگر استفاده شده پرس و جو اجرا میشود
// تغییر اولین عنصر توالی
fibonacci[0] = 99;
// حرکت بر روی نتیجه
foreach (var number in numbersGreaterThanTwoQuery)
{
Console.WriteLine(number);
}
خروجی مثال بالا:
همانطور که میبینید عدد 99 در خروجی مشاهده نمیشود. علت فراخوانی عملگر ToArray است که بلافاصله باعث اجرای پرس و جو شده و خروجی را باز میگرداند . به همین خاطر تغییر عنصر اول توالی ورودی، تاثیری بر روی نتیجهی خروجی ندارد.