عبارات پرس و جو

عبارات پرس و جو، دستورات ویژه‌ای هستند که برای پرس و جوی یک منبع داده با استفاده از LINQ به کار می‌روند. LINQ مجموعه‌ای از متدهای توسعه یافته است که، آنها را صدا می‌زنید و نتایج دلخواه را بدست می‌آورید. این متدها در فضای نامی System.Linq قرار دارند، زمانی که شما قصد دارید از LINQ در پروژه خود استفاده کنید باید این فضای نامی را به کلاس خود اضافه کنید. در زمان اجرا عبارات پرس و جو به متد معادل خود که توسط CLR قابل فهم است تبدیل می‌شوند. در درس بعدی شما یاد می‌گیرید که چگونه با استفاده از زبان LINQ در منابع داده‌ای پرس و جویی را انجام دهید. با یک مثال نحوه‌ی پرس و جو از یک منبع داده‌ای را با استفاده از عبارات پرس و جو تشریح می‌کنیم. به این نکته توجه کنید که در مثال زیر از Linq to Objects استفاده کرده‌ایم، پس برای سادگی از یک آرایه به عنوان منبع داده استفاده می‌کنیم.

  1: using System;
  2: using System.Linq;
  3: 
  4: namespace LinqExample
  5: {
  6:     class Program
  7:     {
  8:         static void Main(string[] args)
  9:         {
 10:             int[] numbers = { 1, 2, 3, 4, 5 };
 11: 
 12:             var result = from n in numbers 
 13:                          select n;         
 14: 
 15:             foreach (var n in result)
 16:             {
 17:                 Console.Write(n + " ");
 18:             }
 19:         }
 20:     }
 21: }
1 2 3 4 5

همانطور که قبلاً گفته شد برای استفاده از زبان Linq باید فضای نام System.Linq به پروژه اضافه شود که این کار در خط دوم انجام داده‌ایم. در خط 10 آرایه‌ای از 5 عدد صحیح را مشاهده می‌کنید. در خط 13-12 ساده‌ترین عبارت پرس و جویی که می‌توان نوشت، قرار دارد. در درس‌های بعدی عبارات پرس و جوی پیشرفته‌تری را می‌نویسیم. عبارت پرس و جوی بالا تمامی اعداد داخل آرایه را به عنوان نتیجه بر می‌گرداند. شما با استفاده از متغیر result می‌توانید به آنها دسترسی داشته باشید. ساختار کلی عبارات پرس و جو در زیر نوشته شده است :

var query = from rangeVar in dataSource
            <other operations>
            select <projection>;

به این نکته توجه کنید که یک عبارت پرس و جو را می‌توان در یک خط کد بنویسید، ولی بهتر آن است که هر قسمت از آن را در یک خط جداگانه نوشت. هر خط از عبارت پرس و جوی بالا یک عبارت (Clause) نامیده می‌شود.

هفت نوع عبارت وجود دارد که شما می‌توانید از آنها داخل یک عبارت پرس وجو استفاده کنید که شامل عبارات from، select، where، orderby، let، join و group-by می‌شود. در این درس فقط از عبارات from و select استفاده می‌شود. عبارات پرس و جو با یک عبارت from شروع می‌شوند. عبارت from از یک متغیر موقت استفاده می‌کند که وظیفه نگهداری موقت یک مقدار از منبع داده را به عهده دارد، بعد از آن کلمه کلیدی in و سپس نام منبع داده قرار می‌گیرد. این بسیار شبیه مکانیزم حلقه foreach است که در آن هر کدام از اعضای مجموعه در یک متغیر موقت قرار می‌گیرند. متغیر موقت به طور خودکار، بسته به نوع اعضای منبع داده، نوع خود را شناسایی می‌کند.

بعد از عبارت from شما می‌توانید از یک یا چند عبارت where، orderby، let، join استفاده کنید. همچنین می‌توانید از چند عبارت from نیز استفاده کنید که در درس‌های بعدی به آن پرداخته می‌شود. در انتهای عبارت پرس و جو، عبارت select قرار می‌گیرد. بعد از کلمه کلیدی select، نام منبع داده که نوع اعضای برگشتی را مشخص می‌کند قرار می‌گیرد. به عنوان مثال اگر مقدار بعد از عبارت select از نوع int باشد، سپس نوع پرس جو مجموعه‌ای از اعداد صحیح خواهد بود. به این نکته توجه کنید که یک عبارت پرس و جو می‌تواند با یک عبارت group-by خاتمه پیدا کند که در درس‌های بعدی به آن پرداخته می‌شود.

خلاصه آنکه یک عبارت پرس و جوی رایج با یک عبارت from همراه با یک متغیر موقت و نام منبع داده شروع می‌شود، در ادامه عبارت from می‌توان از عبارت‌های where، join، orderby، let و در آخر از عبارت‌های select و group-by استفاده می‌شود. اگر شما با زبان SQL آشنایی داشته باشید دستور زبان عبارات پرس و جو برای شما جالب خواهد بود، زیرا کلمه کلیدی from در اول و کلمه کلیدی select در آخر قرار می‌گیرند (در SQL مکان این کلمات بر عکس است). در این صورت نوع مقادیر منبع داده توسط Visual Studio تشخیص داده می‌شود و شما می‌توانید از طریق ویژگی Intellisene آن نوع را مشاهده کنید.

کلمات کلیدی که در یک عبارت پرس و جو به کار برده می‌شود (مانند from و select) نمونه‌ای از contextual keywords ها یا کلمات کلیدی وابسته هستند. این نوع از کلمات فقط در مکان‌ها و شرایط خاصی به عنوان کلمه کلیدی رفتار می‌کنند مثلاً در یک عبارت پرس و جو. به عنوان مثال شما می‌توانید بدون هیچ مشکلی از کلمه select به عنوان نام یک متغیر استفاده کنید در صورتی که از آن متغیر در یک عبارت پرس و جو استفاده نکنید.

اگر به مثالی که قبلاً توضیح داده شد نگاهی بیندازید، می‌بینید که نتیجه در یک متغیر از نوع var قرار گرفته است، به این معنی که این متغیر برای تشخیص نوع داده‌های بازگشتی، از ویژگی Type Inference استفاده می‌کند. همچنین شما می‌توانید نوع داده‌های برگشتی را به طور صریح مشخص کنید، به شکل زیر :

IEnumerable<int> result = from n in numbers
                          select n;

در این حالت شما باید نوع داده‌های برگشتی را از قبل بدانید. توصیه می‌شود از کلمه کلیدی var به جای این حالت استفاده کنید تا از برتری‌های زیاد آن بهره مند شوید. خط 18-15 از مثال قبل مقادیری که توسط پرس و جو برگشت داده شده است را نمایش می‌دهد. برای نمایش مقادیر از یک حلقه ساده foreach استفاده کرده‌ایم. البته یه این نکته توجه داشته باشید که نوع متغیر موقت در مثال قبل var است. در این حالت Compiler نوع عناصر برگشتی را به طور خودکار تشخیص می‌دهد.
در LINQ ویژگی به نام deferred execution (اجرای با تعویق) وجود دارد. به این معنی که عبارات پرس و جو و متدهای LINQ تنها زمانی اجرا می‌شوند که برنامه شروع به خواندن از منبع داده کند یا اینکه بخواهد به یک عنصر از نتیجه پرس وجو دسترسی پیدا کند. در واقع هر عبارت پرس و جو نتیجه یک محاسبه را بر می‌گرداند. نتیجه عبارات تنها یک بار فراخوانی می‌شود و آن زمانی است که کاربر آن را درخواست کند. به عنوان مثال، پرس و جو زمانی اجرا می‌شود که شما بخواهید با استفاده از یک حلقه foreach به نتایج پرس و جو دسترسی داشته باشید.
در درس‌های آینده در رابطه با ویژگی deferred execution توضیحات بیشتری داده خواهد شد. ما با موفقیت اولین عبارت پرس و جوی خود را نوشتیم، اما همانطور که می‌بینید این عبارت فقط داده‌های داخل منبع داده را بر می‌گرداند و کار خاص دیگری را روی آنها انجام نمی‌دهد. در درس‌های آتی تکنیک‌های مختلف دیگر از جمله filtering، ordering، joining و grouping نتایج را یاد می‌گیرید.