با سلام به کاربران عزیز با یکی دیگر از سری آموزش های LINQ در C# در خدمت شما هستیم. در این جلسه قصد داریم با اپراتور های joining آشنا شویم.
joining operators چیست؟
اگر با زبان SQL آشنایی داشته باشید می دانید که اپراتور Join
برای پیوند دادن دو یا چند جدول بر اساس فیلدهایی مشخص و مشترک استفاده می شود. در LINQ نیز کاربرد آن دقیقا مانند زبان SQL است فقط روش اعمال آن متفاوت است که در ادامه با آن آشنا خواهید شد.
عملکرد joining در LINQ به چهار بخش:
INNER JOIN
LEFT OUTER JOIN
CROSS JOIN
GROUP JOIN
تقسیم بندی می شوند که در جدول زیر کاربرد هر یک بررسی شده است:
کاربرد | نام اپراتور |
عناصری را از مجموعه سمت چپ و راست بر اساس یک فیلد مشترک باز می گرداند | INNER JOIN |
عناصر را از مجموعه سمت چپ و عناصر مربوطه از مجموعه سمت راست باز می گرداند | LEFT OUTER JOIN |
هر عنصر از مجموعه ی سمت چپ را به تمامی عناصر مجموعه ی سمت راست اضافه می کند (ربط می دهد) | CROSS JOIN |
عناصر را بر اساس مجموعه ی چپ و راست، به ترتیب گروه مرتب سازی می کند | GROUP JOIN |
پیاده سازی INNER JOIN
با استفاده از این متد می توان دو یا چند مجموعه را بر اساس فیلدهای مشخصی با هم ارتباط داد. توضیح این نوع اپراتورها شاید کمی گیج کننده به نظر برسد. اجازه دهید با بررسی یک مثال آن را توضیح دهیم:
مفهوم کلی Inner Join
الگوی استفاده از join
به صورت زیر است:
دو شی objEmp
و objDept
نماینده ی دو مجموعه ی مختلف هستند که دارای فیلدهای مشخصی می باشند که یک فیلد بین دو مجموعه مشترک است در واقع خط ارتباطی این دو مجموعه (یا جدول) بر اساس فیلد مشترک است که در این الگو، فیلد مشترک DepId
و DeptId
است.
حالا مثال زیر را در نظر بگیرید:
به توضیحات این مثال با دقت توجه کنید:
به کلاس Department
دقت کنید این کلاس دارای دو فیلد DepId
و DepName
است که در Main
، اشیایی از آن در یک لیست با نام objDept
قرار گرفته اند.
حالا کلاس Employee
را در نظر بگیرید این کلاس دارای سه فید EmpId
و Name
و DeptId
می باشد که در Main
اشیایی از آن در یک لیست با نام objEmp
قرار گرفته اند. فیلد DeptId
برای ما اهمیت دارد چون در واقع خط ارتباط دو کلاس Department
و Employee
است. به مقادیر فیلد ها در دو لیست موجود دقت کنید.
در این مثال در اشیای کلاس Department
چند گروه شغلی با ID
هایی مشخص تعریف شده اند مثلا گروه شغلی Health
با ID=3
مشخص شده است. در اشیای کلاس Employee
کارمندان یک سازمان که هر کدام یک ID
مشخص دارند، ثبت شده و در فیلد DeptId
در واقع ID
شغل آن ها ثبت گردیده که اشاره به کلاس Department
دارد.
مثلا رکورد EmpId=1,Name = "Suresh Dasari", DeptId=1
شخصی را با ID=1
و نام Suresh Dasari
و شغل Software
مشخص می کند.
زمانی را در نظر بگیرید که تعداد کارمندان و ردیف های شغلی بسیار زیاد است و قصد داریم افراد را بر اساس ردیف های شغلی دسته بندی کنیم، در اینجا نیاز به استفاده از متد Join داریم که در این مثال از آن استفاده شده است.
در این مثال ابتدا روش Query را بررسی می کنیم:
d
را می توان اشاره گری به objDept
و e
را اشاره گری به objEmp
در نظر گرفت. با استفاده از متد Join
اعلام می کنیم که دو شی به هم متصل (ربط داده) شوند. در خط بعدی فیلد مشترک را بعد از کلمه ی on مشخص می کنیم و شرط تساوی آن را با کلمه ی equals
اعلام می کنیم. خب به عبارت بعد از Select
دقت کنید در انتها ما باید اعلام کنیم که اطلاعاتی که از دو جدول با هم Join
شدند بر چه اساس و فیلد هایی باید به عنوان خروجی در نظر گرفته شوند.
در این مورد e.Name
از کلاس Employee
با نام EmployeeName(نام دلخواه)
و d.DepName
از کلاس Department
با نام DepartmentName(نام دلخواه)
خروجی مورد نظر ما است. مشاهده می کنید که در حلقه ی foreach
این دو توسط item
قابل دستیابی است.
EmployeeName = e.Name
و DepartmentName = d.DepName
را متوجه نشدید عبارت anonymous type را در اینترنت جست و جو کنید.خروجی مثال Join
همان طور که در خروجی مشخص است فقط افرادی که دارای DeptId
هستند، نشان داده شده اند.
برای نوشتن کد به روش Extension به صورت زیر عمل می کنیم:
خروجی این کد کاملا مشابه با حالت قبل است و فقط نوشتن آن کمی پیچیده تر است.
پیاده سازی LEFT OUTER JOIN
این پیاده سازی تمامی عناصر موجود در مجموعه ی چپ را بر اساس عناصر موجود در مجموعه ی سمت راست بر می گرداند. به مثال قبلی دقت کنید فقط اسم کارمندانی در خروجی قابل مشاهده است که فیلد DeptId
آن ها دارای مقدار است. در واقع می توان این چنین تصور کرد که اولویت با نشان دادن اطلاعات مجموعه ی سمت چپ است. عکس زیر مفهوم کلی Left Outer Join را نشان می دهد.
مفهوم کلی Left Outer Join
الگوی استفاده از آن تا حدودی مانند Inner Join
است اما دارای تفاوت های کوچکی است که می توانید در الگوی زیر مشاهده کنید:
ابتدا به متد DefaultIfEmpty
دقت کنید. در اینجا بر روی شی empDept
اعمال شده این شی حاوی اطلاعات دو مجموعه بر اساس دو فیلد مشترک است. در چند خط بعدی بر روی ed
که حاوی اطلاعات empDept.DefaultIfEmpty
است یک شرط قرار داده شده که اگر ed.DepName
دارای مقدار نبود عبارت No Department نمایش داده شود در غیر این صورت DepName
مربوطه چاپ می شود. به طور کلی خروجی متد DefaultIfEmpty
برای فیلد هایی که مقدار ندارند 0 و برای باقی فیلدهایی که داری مقدار هستند، برابر با مقدار خود فیلد است.
برای درک بهتر به مثال زیر توجه کنید:
کد بالا دقیقا کد استفاده شده برای مثال اول است فقط تغییراتی کوچک در آن انجام شده تا عملیات Left Outer Join را پیاده سازی کند. کد را در IDE خود اجرا کنید و خروجی را مشاهده کنید می بینید که اسم تمامی کارمندان در خروجی نشان داده شده (مجموعه ی چپ) و مواردی که DepName
آن ها مقدار ندارد با No Department مشخص شده است. به یاد دارید که در خروجی مثال اول فقط اسامی کارکنانی که دارای DepName
بودند در خروجی قابل مشاهده بود.
مثال Left Outer Join
نوشتن کد به صورت Query برای Left Outer Join کمی پیچیده و مشکل است و نیازمند به کارگیری متدهایی است که تا الان بررسی نشده اند به همین دلیل آن را در جایی مناسب بررسی خواهیم کرد.
پیاده سازی CROSS JOIN
در این روش از Join
تمامی عناصر مجموعه ی سمت چپ به تمامی عناصر مجموعه ی سمت راست نسبت داده می شوند. به شکل زیر که نمایی کلی از Cross Join است دقت کنید:
مفهوم کلی Cross Join
الگوی استفاده از آن به صورت زیر است:
به مثال زیر توجه کنید:
همانطور که مشاهده می کنید در پیاده سازی Cross Join
اصلا واژه ی Join
به کار نرفته است.
مثال اول Cross Join
اگر کد را اجرا کنید و خروجی را مشاهده کنید در نگاه اول شاید عجیب به نظر برسد ولی این روش پیاده سازی Join برای تولید داده های سطری و ستونی مرتب به کار می رود ولی کاربرد چندانی ندارد. به همین دلیل از توضیح بیشتر آن پرهیز می کنیم اما برای درک کلی کاربرد آن مثال جالب زیر را در نظر بگیرید:
خروحی مثال دوم Cross Join
پیاده سازی GROUP JOIN
یکی از مهم ترین و پر کاربردترین پیاده سازی های Join
استفاده از Group Join است. برای فهم بهتر این کاربرد توضیح آن را در قالب مثال بررسی می کنیم.
مثال:
این مثال دقیقا مانند مثال بررسی شده در قسمت Left Outer Join است، فقط نوع نمایش خروجی آن منظم تر است. توجه داشته باشید تا خط کد select new
کاملا مشابه قبل پیاده سازی شده اما مهم ترین بخشی که باعث می شود داده ها به صورت منظم در خروجی نمایان شوند Query دومی است که حاصل آن در Employees
ذخیره می شود. لازم به ذکر است نام Employees کاملا اختیاری بوده و قابل تغییر است. در این مثال از empDept
یک Query گرفتیم و با استفاده از متد orderby
نام کارکنان را مرتب سازی کرده ایم که در نتیجه ی آن خروجی منظم خواهیم داشت. به شکل زیر که خروجی این مثال است توجه کنید و با خروجی حاصل شده از مثال مربوط به Left Outer Join مقایسه کنید.
خروجی مثال Group Join
همان طور که مشاهده می کنید هر ردیف شغلی با کارمندان بخش خود به صورت مرتب در خروجی نشان داده شده اند. حالا به قسمتی از کد که foreach
در آن به کار رفته، دقت کنید. وظیفه ی این بخش چاپ صحیح و مرتب اطلاعاتی است که در result
ذخیره شده اند. حلقه ی اول وظیفه ی چاپ DepartmentName
را دارد.
به پیمایش کننده ی empGroup
دقت کنید که به دو شی DepartmentName
و Employees
دسترسی دارد. DepartmentName
از نوع string
است که توسط حلقه ی اول پیمایش و چاپ می شود اما شی Employees
از نوع Query
بوده پس برای چاپ آن نیاز به یک حلقه ی داخلی است تا اطلاعات آن را پیمایش و چاپ کند.
این قسمت از آموزش هم به پایان رسید. توجه داشته باشید مبحث Join
کمی مشکل بوده و توضیح کاربرد آن ها مشکل تر و نیاز به حل مثال هایی بیشتر دارد پس بهترین راه ممکن برای یادگیری عمیق آن حل تمرین بسیار است.
موفق باشید.
منبع: روکسو