مشخصات مقاله
-
1507
-
0.0
-
5125
-
0
-
0
آموزش گام به گام نوشتن Query های LINQ در زبان CSharp
کلیه حقوق مادی و معنوی این مقاله متعلق به آموزشگاه تحلیل داده می باشد و هر گونه استفاده غیر قانونی از آن پیگرد قانونی دارد.
آموزش گام به گام نوشتن Query های LINQ در زبان C#
در این مبحث نحوه ی نوشتن کوئری های LINQ با استفاده از امکانات و قابلیت های زبان C#را به شما آموزش می دهیم.
پیش نیاز: برای این آموزش لازم است حداقل ویرایش 2008 ویژوال استودیو را بر روی رایانه ی خود نصب داشته باشید.
ایجاد یک پروژه ی C#
1. در گام نخست، محیط برنامه نویسی Visual Studio را راه اندازی نمایید.
2. در نوار منو، به ترتیب گزینه های File، New، Project را برای ساخت پروژه ی جدید انتخاب کنید. کادر محاوره ای New Project باز خواهد شد.
3. به ترتیب گره های Installed، Templates، Visual C# را باز کرده، سپس گزینه ی Console Application را انتخاب نمایید.
4. در کادر متن Name، یک اسم به عنوان اسم پروژه وارد نموده و یا اسمی که به صورت پیش فرض ارائه شده را بپذیرد. حال بر روی دکمه ی OK را کلیک کنید. می بینید که پروژه ی جدید در پنجره یSolution Explorer به نمایش در می آید.
5. همان طور که می بینید پروژه ی جدید شما ارجاعی به System.Core.dll و نیز یک دستور using برای وارد کردن کتابخانه ی (namespace) System.Linqدر برنامه ی جاری دارد.
ایجاد یک منبع داده مقیم در حافظه (in-Memory Data Source)
منبع داده ی ای که از آن کوئری می گیریم یک لیست ساده از اشیا Student می باشد. هر سطر (رکورد) student یک اسم کوچک (first name)، فامیلی (last name) و نیز یک آرایه از اعداد صحیح (integer) دارد که نشانگر نمره ی دانش آموزان در کلاس می باشد. کد زیر را در پروژه ی خود کپی کنید. به ویژگی های زیر دقت کنید:
1. کلاس Student از دو property تشکیل می شود.
2. تمامی اشیا student در این لیست با یک object initializer (ایجاد شی جدید با کلیدواژه ی new) تنظیم و مقداردهی اولیه می شوند.
3. خود List با یک collection initializer (ایجاد کننده ی لیست جدید) ایجاد و مقداردهی اولیه می شود.
کل این ساختار بدون فراخوانی صریح هیچ گونه constructor یا دسترسی صریح به اعضای کلاس ایجاد و مقداردهی اولیه شده است.
افزودن منبع داده به پروژه
1. کلاس Student و لیست student های ایجاد شده با initializer را به کلاس program در پروژه ی خود اضافه کنید.
public class Student
{
public string First { get;set;}
public string Last { get;set;}
public int ID { get;set;}
public List<int>Scores;
}
// Create a data source by using a collection initializer.
static List
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int>{97, 92, 81, 60}},
new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int>{75, 84, 91, 39}},
new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int>{88, 94, 65, 91}},
new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int>{97, 89, 85, 82}},
new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int>{35, 72, 91, 70}},
new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int>{99, 86, 90, 94}},
new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int>{93, 92, 80, 87}},
new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int>{92, 90, 83, 78}},
new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int>{68, 79, 88, 92}},
new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int>{99, 82, 81, 79}},
new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int>{96, 85, 91, 60}},
new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int>{94, 92, 91, 91} }
};
اکنون برای افزودن student جدید به لیست Students:
2. یک Student جدید به لیست Students اضافه کرده و اسم و نمره ی دلخواه را انتخاب کنید.
نوشتن Query
جهت ایجاد یک کوئری ساده:
1. در متد Main برنامه، یک کوئری ساده بنویسید که پس از اجرا، لیستی از تمامی دانش آموزانی که نمره اولین آزمون آن ها بالاتر از 90 باشد را برگرداند. همان طور که می بینید، به دلیل اینکه کل شی student انتخاب شده، نوع متغیری که دستور کوئری در آن ریخته می شود، IEnumerable<Student> می باشد. اگرچه می توانستیم از کلیدواژه ی var برای نوع دهی متغیر به صورت ضمنی (تعریف متغیر با نوع نامشخص) استفاده کنیم، با این حال تصمیم گرفتیم برای شرح و نمایش دقیق نتایج از نوع دهی صریح استفاده کنیم.
همچنین با توجه به مثال می بینید که متغیر تعریف شده داخل عبارت کوئری، student، به عنوان ارجاعی به هر شی student در منبع داده عمل می کند و در نتیجه دسترسی به اشیا عضو (در منبع داده) را فراهم می آورد.
// Create the query.
// The first line could also be written as "var studentQuery ="
IEnumerable
from student in students
where student.Scores[0] >90
select student;
اجرای Query
به منظور اجرای کوئری:
1. حال دستور حلقه ی foreach را بنویسید که سبب اجرای کوئری می شود. به نکته های زیر توجه کنید:
1) تمامی المان هایی که در خروجی مشاهده می کنید از طریق متغیر تعریف شده در دستور حلقه ی foreach قابل دسترسی می باشد.
2) نوع متغیر مزبور Student بوده و با نوع متغیر دربرگیرنده ی دستور کوئری " IEnumerable<Student>" سازگار می باشد.
2. پس از افزودن این کد به برنامه، برنامه را با گرفتن کلیدهای Ctrl + F5، کامپایل (build) و اجرا نمایید. نتایج برنامه در پنجره ی کنسول به نمایش در می آید.
// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
Console.WriteLine("{0}, {1}", student.Last, student.First);
}
// Output:
// Omelchenko, Svetlana
// Garcia, Cesar
// Fakhouri, Fadi
// Feng, Hanying
// Garcia, Hugo
// Adams, Terry
// Zabokritski, Eugene
// Tucker, Michael
افزودن یک شرط دیگر
1. می توانید چندین شرط بولی را در عبارت where ترکیب کرده و بدین وسیله نتیجه ی کوئری را محدودتر نمایید. کد زیر شرطی را اعمال می کند که نتیجه ی آن داشن آموزانی است که نمره ی اول آن ها بالاتر از 90 و نمره آزمون آخر آن ها پایین تر از 80 باشد. شرطی که در این عبارت where نوشته می شود باید به صورت زیر باشد:
where student.Scores[0] >90 &&student.Scores[3] <80
ویرایش Query
برای مرتب سازی نتیجه ی query:
1. زمانی که نتایج یا خروجی کوئری مرتب سازی شده، قطعا مشاهده و پویش آن ساده تر می باشد. می توانید خروجی را (که به صورت دنباله ای از مقادیر برگردانده شده) بر اساس هر یک از فیلدهای قابل دسترسی در المان منبع مرتب نمایید. به طور مثال، دستور orderby نتایج را به ترتیب حروف الفبا از A تا Z بر اساس فامیلی هر دانش آموز مرتب سازی می کند. کلیدواژه ی orderby را بلافاصله پس از عبارت where و پیش از دستور select درج نمایید.
orderby student.Last ascending
2. حال عبارت orderby را طوری تغییر دهید که نتایج را به ترتیب نزولی نمایش دهد.
orderby student.Scores[0] descending
3. دستور WriteLine را گونه ای ویرایش نمایید که بتواند نتایج را نمایش دهد:
Console.WriteLine("{0}, {1} {2}", student.Last, student.First, student.Scores[0]);
برای گروه بندی نتایج:
1. گروه بندی یک قابلیت بسیار پرطرفدار است که در عبارت های کوئری مورد استفاده می گیرد. کوئری که عبارت group در آن بکار گرفته شده یک دنباله از گروه ها را به عنوان خروجی بازیابی می کند. هر گروه علاوه بر Key (المانی که خروجی بر اساس آن گروه بندی می شود)، دنباله ای را متشکل از تمامی اعضای آن گروه برمی گرداند. دستور زیر دانش آموزان را بر اساس حرف اول فامیلی آن ها (همان Key) گروه بندی می کند.
// studentQuery2 is an IEnumerable<>
var studentQuery2 =
from student in students
group student by student.Last[0];
2. همان طور که مشاهده می کنید نوع متغیری که عبارت کوئری درآن ذخیره شده، تغییر کرده است. این بار کوئری یک دنباله از گروه ها را به عنوان خروجی بازمی گرداند که از یک کلید از نوع achar و دنباله ای از اشیا student تشکیل شده است. از آنجایی که نوع متغیر حاوی دستور کوئری تغییر کرده، دستور حلقه ی foreach نیز پیرو آن بایستی به ترتیب زیر ویرایش گردد:
// studentGroup is a IGrouping
foreach (var studentGroup in studentQuery2)
{
Console.WriteLine(studentGroup.Key);
foreach (Student student in studentGroup)
{
Console.WriteLine(" {0}, {1}",
student.Last, student.First);
}
}
// Output:
// O
// Omelchenko, Svetlana
// O'Donnell, Claire
// M
// Mortensen, Sven
// G
// Garcia, Cesar
// Garcia, Debra
// Garcia, Hugo
// F
// Fakhouri, Fadi
// Feng, Hanying
// T
// Tucker, Lance
// Tucker, Michael
// A
// Adams, Terry
// Z
// Zabokritski, Eugene
3. کلیدهای Ctrl + F5 را فشار دهید تا برنامه اجرا گردد و نتایج آن را در پنجره ی Console مشاهده نمایید.
برای اینکه متغیرها را به صورت ضمنی (با استفاده از کلیدواژه ی var) نوع دهی کنید:
1. می توانید کوئری و دستور حلقه ی foreach خود را بسیار آسان تر به وسیله ی کلیدواژه ی var بنویسید (با var نوع متغیر را به صورت ضمنی مشخص کنید). var نوع اشیا را تغییر نمی دهد، بلکه تنها به کامپایلر دستور می دهد نوع آن ها را در زمان برگرداندن کد به زبان ماشین تشخیص دهد. نوع متغیرهای studentQuery و group را به ترتیب به var تغییر داده و کوئری را مجددا اجرا نمایید. با بررسی مثال متوجه می شوید که متغیر موجود در دستور حلقه ی درونی همچنان با Student نوع دهی شده و در عین حال کوئری به درستی قبل عمل می کند. نوع متغیر s در دستور حلقه ی foreach درونی را به var تغییر دهید و سپس کوئری را بار دیگر اجرا کنید. خواهید دید که خروجی با نتیجه ی نمونه ی قبلی یکسان می باشد.
var studentQuery3 =
from student in students
group student by student.Last[0];
foreach (var groupOfStudents in studentQuery3)
{
Console.WriteLine(groupOfStudents.Key);
foreach (var student in groupOfStudents)
{
Console.WriteLine(" {0}, {1}",
student.Last, student.First);
}
}
// Output:
// O
// Omelchenko, Svetlana
// O'Donnell, Claire
// M
// Mortensen, Sven
// G
// Garcia, Cesar
// Garcia, Debra
// Garcia, Hugo
// F
// Fakhouri, Fadi
// Feng, Hanying
// T
// Tucker, Lance
// Tucker, Michael
// A
// Adams, Terry
// Z
// Zabokritski, Eugene
اکنون جهت گروه بندی نتیجه ی کوئری بر اساس مقدار کلید (ورودی که بر اساس آن خروجی مرتب سازی می شود):
1. زمانی که کوئری پیشین را اجرا می کنید، متوجه می شوید که نتیجه به ترتیب حروف الفبا مرتب نشده است. برای ویرایش آن، می بایست پس از عبارت group، یک دستور orderby لحاظ نمایید. برای استفاده از عبارت orderby، ابتدا بایستی یک شناسه که قرار است به عنوان ارجاعی به گروه های ایجاد شده توسط عبارت group ایفای نقش کند، ارائه نمایید (یک متغیر با اسم یا شناسه ی معین (studentGroup) فراهم نمایید که خروجی دستور group در آن ذخیره گردد و سپس اسم آن متغیر را در عبارت orderby برای مرتب سازی المان های آن بر اساس مقدار کلید قرار دهید). همان طور که در مباحث پیشین ذکر شد، این شناسه را می بایست با استفاده از کلیدواژه ی into در دستور درج کنید:
var studentQuery4 =
from student in students
group student by student.Last[0] into studentGroup
orderby studentGroup.Key
select studentGroup;
foreach (var groupOfStudents in studentQuery4)
{
Console.WriteLine(groupOfStudents.Key);
foreach (var student in groupOfStudents)
{
Console.WriteLine(" {0}, {1}",
student.Last, student.First);
}
}
// Output:
//A
// Adams, Terry
//F
// Fakhouri, Fadi
// Feng, Hanying
//G
// Garcia, Cesar
// Garcia, Debra
// Garcia, Hugo
//M
// Mortensen, Sven
//O
// Omelchenko, Svetlana
// O'Donnell, Claire
//T
// Tucker, Lance
// Tucker, Michael
//Z
// Zabokritski, Eugene
پس از اجرای کوئری می بینید که گروه ها بر اساس ترتیب حروف الفبا مرتب سازی شده اند.
برای تعریف متغیر جدید با شناسه یا نام مشخص داخل عبارت کوئری:
1. می توان با استفاده از کلیدواژه ی let یک متغیر جدید با نام مشخص برای ذخیره ی نتیجه هر عبارتی (از جمله عبارت محاسباتی) داخل کوئری بهره گرفت. این متغیر با نام جدید می تواند صرفا یک آیتمی باشد که کار شما را آسان تر می کند و یا همان طور که در نمونه ی زیر مشاهده می کنید، کارایی را افزایش دهد. به عنوان مثال، با استفاده از let یک متغیر داخل کوئری تعریف می کنیم که نتیجه ی محاسبه ی یک عملیات (جمع نمرات دانش آموزان) را در خود ذخیره می کند.
کوئری زیر یک لیست از دانش آموزانی برمی گرداند که معدل آن ها پایین تر از نمره ی آزمون اول می باشد.
// studentQuery5 is an IEnumerable
// This query returns those students whose
// first test score was higher than their
// average score.
var studentQuery5 =
from student in students
let totalScore = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
where totalScore / 4 <>
select student.Last + " " + student.First;
foreach (string s in studentQuery5)
{
Console.WriteLine(s);
}
// Output:
// Omelchenko Svetlana
// O'Donnell Claire
// Mortensen Sven
// Garcia Cesar
// Fakhouri Fadi
// Feng Hanying
// Garcia Hugo
// Adams Terry
// Zabokritski Eugene
// Tucker Michael
به منظور استفاده از روش نوشتن کوئری با ساختار متد (method syntax):
1. همان طور که در مباحث گذشته گفته شد، برخی از کوئری ها را فقط می بایست به روش method syntax نوشت (نگارش نمود). کد زیر مجموع نمرات دانش آموزان را بدست می آورد و سپس تابع Average() را برای محاسبه ی معدل کل کلاس، بر روی نتیجه ی کوئری فراخوانی می کند.
کوئری زیر معدل کل کلاس را بدست می آورد:
var studentQuery6 =
from student in students
let totalScore = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
select totalScore;
double averageScore = studentQuery6.Average();
Console.WriteLine("Class average score = {0}", averageScore);
// Output:
// Class average score = 334.166666666667
جهت انجام تبدیل در دستور select:
1. همان طور که می دانید برخی کوئری ها نتیجه ای را به عنوان خروجی برمی گردانند که با المان های اصلی منبع داده (که از آن کوئری گرفته می شود) کمی متفاوت است. برای مثال، کوئری را طوری تنظیم می کنیم که به عنوان خروجی اسامی دانش آموزانی را برگرداند که فامیلی آن ها Garcia می باشد.
برای پیاده سازی این مثال، کد زیر را جایگزین کوئری نمونه ی قبلی نمایید.
IEnumerable<string>studentQuery7 =
from student in students
where student.Last == "Garcia"
select student.First;
Console.WriteLine("The Garcias in the class are:");
foreach (string s in studentQuery7)
{
Console.WriteLine(s);
}
// Output:
// The Garcias in the class are:
// Cesar
// Debra
// Hugo
همان طور که می بینید کوئری درج شده در بالا، یک دنباله از مقادیر رشته ای را به عنوان خروجی واکشی می کند. به همین خاطر نوع متغیر تعریف شده در حلقه ی foreach از نوع string می باشد.
2. معدل کل دانش آموزان کلاس، همان طور که در مثال بخش قبلی محاسبه شد، معادل حدودا 334 می باشد. حال برای تولید لیستی از دانش آموزان که مجموع نمرات آن ها بالاتر از معدل کل کلاس می باشد، به همراه شماره ی هر دانش آموز (Student ID)، می توان از متغیر با نوع ناشناس (anonymous type) در دستور select استفاده نمود.
var studentQuery8 =
from student in students
let x = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
where x >averageScore
select new { id = student.ID, score = x };
foreach (var item in studentQuery8)
{
Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score);
}
// Output:
// Student ID: 113, Score: 338
// Student ID: 114, Score: 353
// Student ID: 116, Score: 369
// Student ID: 117, Score: 352
// Student ID: 118, Score: 343
// Student ID: 120, Score: 341
// Student ID: 122, Score: 368