کانال بله, جهت پشتیبانی و اطلاع رسانی کانال بله, جهت پشتیبانی و اطلاع رسانی
عضویت

مقدمه ای بر کوئری های LINQ در زبان C-Sharp

دوره آموزشی Asp.net

کلیه حقوق مادی و معنوی این مقاله متعلق به آموزشگاه تحلیل داده می باشد و هر گونه استفاده غیر قانونی از آن پیگرد قانونی دارد.

مقدمه ای بر کوئری های LINQ در زبان C#

Query یک عبارت است که داده هایی را از یک data source (منبع داده) بازیابی می کند. Query ها معمولا در زبان پرس و جو خاص خود نوشته می شوند. درطول زمان، زبان های مختلفی ویژه ی منبع داده های متفاوت ارائه شده، به عنوان مثال می توان به SQL برای پایگاه داده های رابطه ای (relational databases) و XQuery برای زبان نشان گذاری توسعه پذیر XML اشاره کرد. بنابراین، توسعه دهندگان مجبور بودند برای هر یک از این data source یا data format ها، یک زبان پرس و جوی جدید و منحصربفرد را بیاموزند. LINQ یک مدل یکپارچه و ثابت برای کار با داده ها در تمامی data source ها و فرمت ها ارائه می دهد. در کوئری های LINQ، برنامه نویس مدام به شی سروکار دارد. برای کوئری گرفتن از داده ها و تبدیل آن ها به فایل های XML، پایگاه داده های SQL، Dataset های ADO.NET، collection های .NET و هر فرمت دیگری که LINQ provider پشتیبانی می کند، از همان الگوی کدنویسی پایه استفاده می شود.   

سه بخش مهم عملیات یک Query

عملیات مربوط به Query های LINQ، به سه بخش کلی تقسیم می شوند:

1. دسترسی به data source.

2. ایجاد یا نوشتن Query.

3. اجرای Query.

مثال زیر نشان می دهد چگونه سه بخش ذکر شده در source code نوشته و پیاده سازی می شوند. کد حاضر برای سهولت از یک آرایه از نوع integer (عدد صحیح) به مثابه ی data source استفاده می کند، اما، می توان آن را برای دیگر نوع data source ها نیز بکار برد. این مثال در سرتاسر این مقاله ی آموزشی مورد اشاره قرار می گیرد.  

class IntroToLINQ

{       

   static void Main()

   {

       // The Three Parts of a LINQ Query:

       // 1. Data source.

       int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

 

       // 2. Query creation.

       // numQuery is an IEnumerable

       var numQuery =

           from num in numbers

           where (num % 2) == 0

           select num;

 

       // 3. Query execution.

       foreach (int num in numQuery)

       {

           Console.Write("{0,1} ", num);

       }

   }

}

تصویر زیر عملیات مربوط به یک Query را به طور کامل نمایش می دهد. در LINQ، اجرای کوئری از خود آن کامل متمایز است. به عبارتی دیگر، به صرف تعریف یک متغیر از نوع query variable، داده ای از data source بازیابی نمی شود.      

آموزش Asp.net

Data Source

در مثال قبلی، از آنجایی که data source یک آرایه است، صریحا از اینترفیس جنریک IEnumerable<T> پشتیبانی می کند. بنابراین می توان به وسیله ی LINQ از آن کوئری گرفت. همان طور که می بینید، یک کوئری در دستور foreach اجرا شده و foreach برای اینکه بتواند داده ها را بخواند به IEnumerable یا IEnumerable<T> نیاز دارد. نوع هایی که از IEnumerable<T> یا یک interface مشتق همچون generic IQueryable<T> پشتیبانی می کنند، در اصطلاح queryable types خوانده می شوند.

نوع queryable به هیچ ویرایشی برای ایفای نقش به عنوان یک منبع داده ی LINQ نیاز ندارد. در صورتی که Source data از قبل در قالب یک نوع queryable در حافظه موجود نمی باشد، LINQ provider بایستی نوع آن را نمایش دهد. به طور مثال، LINQ to XML یک فایل XML را در نوع queryable XElement بارگذاری می کند: 

// Create a data source from an XML document.
// using System.Xml.Linq;
XElement contacts = XElement.Load(@"c:\myContactList.xml");

در LINQ to SQL، ابتدا یک Object Relational Mapping در زمان طراحی یا به صورت دستی و یا با استفاده از Object Relational Designer (O/R Designer) ایجاد می کنیم. کوئری را برای بازیابی داده از اشیا تنظیم می کنیم، سپس خود LINQ to SQL ارتباط با پایگاه داده را در زمان اجرا (run-time) مدیریت می کند. در مثال زیر، Customers یک جدول در پایگاه داده می باشد. نوع نتیجه ی کوئری، IQueryable<T>    ، از نوع IEnumerable<T> مشتق می شود.

Northwnd db = new Northwnd(@"c:\northwnd.mdf");
 
// Query for customers in London.
IQueryablecustQuery =
   from cust in db.Customers
   where cust.City == "London"
   select cust;

توجه داشته باشید که منبع داده LINQ می تواند هر شی ای که از اینترفیس جنریک IEnumerable<T> پشتیبانی می کند یا هر interface ای که از آن ارث بری دارد، باشد.

نکته: نوع داده هایی نظیر ArrayList که از اینترفیس IEnumerable غیر جنریک (non-generic) پشتیبانی می کنند نیز می توانند به عنوان منبع داده LINQ ایفای نقش کنند.

Query

Query مشخص می کند چه داده هایی از منبع یا منابع داده بازیابی شود. در صورت تمایل می توان در کوئری مشخص کرد که داده ها چگونه قبل از اینکه برگردانده شوند، مرتب سازی، گروه بندی و شکل دهی شوند. query داخل یک query variable (متغیر از نوع کوئری) ریخته شده و با یک عبارت query مقداردهی اولیه می شوند. برای آسان سازی نوشتن query، C# یک ساختار نگارشی ویژه ارائه کرده است.

Query ذکر شده در مثال اول، تمامی اعداد زوج را از آرایه ی از نوع عدد صحیح بازیابی می کنند. دستور query حاوی سه عبارت می باشد: from، where و select. (در صورت آشنایی با SQL، به طور قطع متوجه شده اید که ترتیب ذکر عبارت ها در دستور، معکوس شده است.) عبارت from در واقع منبع داده ای که اطلاعات بایستی از آن استخراج شود را مشخص می کند. عبارت where فیلتر اعمال می کند و در نهایت عبارت select نوع المان بازگشتی را تعیین می کند.

نکته ی قابل توجه این است که خود Query variable اقدام خاصی را انجام نمی دهد و هیچ اطلاعاتی را بازگردانی نمی کند. بلکه تنها اطلاعات مورد نیاز برای بازگردانی نتایج مد نظر را در جایی ذخیره می کند که بعده ها و در زمان اجرا کوئری مورد استفاده قرار می گیرد.

Query Execution

deferred execution (اجرای با تاخیر): همان طور که پیش تر گفته شد، query variable صرفا دستورات پرس و جو را در خود ذخیره می کند. اجرای حقیقی کوئری تا زمانی که شما به وسیله ی دستور foreach در آن حلقه نزده و اطلاعات آن را کامل نخوانده اید، به تاخیر افتاده و اجرا نمی شود. از این رخداد به نام deferred execution یاد می شود:

     // Query execution. 
foreach (int num in numQuery)
{
   Console.Write("{0,1} ", num);
}

دستور foreach همان جایی است که نتایج در آن بازیابی می شوند. به عنوان مثال، در کوئری قبلی، تمامی مقادیر تک تک به ترتیب داخل متغیر num ریخته می شوند. به این خاطر که خود query variable هیچگاه نتایج کوئری را نگه نمی دارد، می توانید آن را بارها اجرا کنید. به عنوان مثال، ممکن است پایگاه داده ای داشته باشید که به مداوم توسط برنامه ی دیگری بروز آوری می شود. می توان در برنامه ی خود یک کوئری بنویسید که جدیدترین داده ها بازیابی کند. برای این منظور می توانید کوئری مزبور را به طور مکرر و در فواصل زمانی معین اجرا کنید تا هر بار نتایج متفاوتی واکشی گردد.   

اجرای بی درنگ Query  

Query هایی که توابع تجمعی (aggregate) را بر روی مجموعه ای از المان های منبع داده اجرا می کنند، می بایست ابتدا داخل المان ها بچرخند. Count، Max، Average و First از این دست توابع هستند. توابع نام برده بدون یک دستور صریح foreach هم اجرا می شوند زیرا خود Query بایستی برای واکشی نتایج ناچارا از دستور foreach استفاده کند. لازم به ذکر است که این توابع تنها یک مقدار را به عنوان خروجی برمی گرداند (خروجی آن ها به هیچ وجه IEnumerablecollection نخواهد بود). کوئری زیر اعداد زوج را از آرایه برمی گرداند:

var evenNumQuery = 
   from num in numbers
   where (num % 2) == 0
   select num;
 
int evenNumCount = evenNumQuery.Count();

برای اینکه کوئری را مجبور به اجرای بلادرنگ کرده و نتایج آن را موقتا ذخیره کنیم، می توانید متدهای   ToList<TSource> یا ToArray<TSource> را صدا بزنیم.  

List<int>numQuery2 =
   (from num in numbers
    where (num % 2) == 0
    select num).ToList();
 
// or like this:
// numQuery3 is still an int[]
 
var numQuery3 =
   (from num in numbers
    where (num % 2) == 0
    select num).ToArray();

 

همچنین می توانید اجرای بلادرنگ را با قرار دادن حلقه ی foreach بلافاصله پس از عبارت query اعمال کنید. اما، با فراخوانی متدهای ToList یا ToArray نه تنها کوئری را بلافاصله اجرا می کنید، بلکه می توانید کلیه ی داده ها را در یک شی collection موقتا ذخیره (cache) نمایید.

1395/01/20 4721 1447
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...