عبارت join – انجام یک عمل inner join

Inner joins ساده‌ترین عمل اتصال است. این نوع اتصال یک خروجی شبیه یک جدول بر می‌گرداند. به این معنی اگر شما به نتیجه پرس و جو نگاه کنید شبیه به یک جدولی خواهد بود که هر سلول از آن یک مقدار دارد. فرض کنید دو جدول در پایگاه داده به نام‌های Authors و Books دارید. جدول Author شامل اطلاعاتی در مورد مؤلف‌های مختلف است. در جدول Books نیز اطلاعاتی در مورد کتاب‌ها همراه با شناسه مؤلف آن کتاب وجود دارد. اتصال دو جدول با استفاده از Inner joins یک خروجی شبیه شکل زیر بر می‌گرداند.

Author

Book

John Smith Little Blue Riding Hood
John Smith Snow Black
John Smith Hanzel and Brittle
Harry Gold My Rubber Duckie
Harry Gold He Who Doesn’t Know His Name
Ronald Schwimmer The Three Little Piggy Banks

هر مؤلف می‌تواند چندین کتاب مربوط به خود داشته باشد. همانطور که در بالا مشاهده می‌کنید مؤلف John Smith سه کتاب، مؤلف Harry Gold دو کتاب و Ronald Schwimmer یک کتاب تألیف کرده‌اند.
join-clause-1001
هر آیتم در منبع داده‌ی داخلی با آیتم نظیر خود در منبع داده‌ی خارجی ترکیب شده و سپس یک آیتم جدید را تشکیل می‌دهند. اولین آیتم داخلی به دنبال تمامی آیتم‌های نظیر خود در منبع خارجی می‌گردد و با آنها ترکیب می‌شود و تشکیل یک آیتم جدید می‌دهد. برای دومین، سومین و… داخلی هم همین عمیل انجام می‌گیرد. برای تشخیص اینکه آیا دو آیتم با هم نظیر هستند، هر دو آیتم باید دارای یک خاصیت یا عضو باشند که از لحاظ مساوی بودن با یکدیگر مقایسه شوند. همانطور که در شکل بالایی می‌بینید آیتم چهارم در منبع داده‌ی خارجی در نتیجه پرس و جو قرار نگرفته است. هر آیتم در منبع داده‌ی خارجی که دارای عضو نظیر در منبع داده‌ی داخلی نباشد در نتیجه قرار نمی‌گیرد. همین عمل در رابطه با آیتم‌های موجود در منبع داده‌ی داخلی هم صدق می‌کند.
به مثال زیر توجه کنید. در این مثال دو کلاس به نام‌های Author و Book تعریف شده‌اند.

class Author
{
    public int AuthorId { get; set; }
    public string Name { get; set; }
}

class Book
{
    public int AuthorId { get; set; }
    public string Title { get; set; }
}

همانطور که در مثال بالا مشاهده می‌کنید هر دو کلاس دارای خاصیت مشابهی به نام AuthorId هستند. این خاصیت برای تشخیص آیتم‌های نظیر در طی عملیات اتصال استفاده می‌شود. به این نکته توجه کنید که نام خاصیت‌ها لازم نیست با یکدیگر مساوی باشد اما باید هر دو خاصیت دارای نوع داده‌ای یکسانی باشند. در کد زیر اشیایی از هر دو کلاس Author و Books ایجاد شده‌اند. هر کتاب با استفاده از خاصیت AuthorId خود به یک مؤلف اشاره می‌کند.

   1: class Program
   2: {
   3:     public static void Main(string[] args)
   4:     {
   5:         Author[] authors = new Author[] 
   6:         {
   7:             new Author() { AuthorId = 1, Name = "John Smith" },
   8:             new Author() { AuthorId = 2, Name = "Harry Gold" },
   9:             new Author() { AuthorId = 3, Name = "Ronald Schwimmer" },
  10:             new Author() { AuthorId = 4, Name = "Jerry Mawler" }
  11:         };
  12: 
  13:         Book[] books = new Book[] 
  14:         {
  15:             new Book() { AuthorId = 1, Title = "Little Blue Riding Hood" },
  16:             new Book() { AuthorId = 3, Title = "The Three Little Piggy Banks" },
  17:             new Book() { AuthorId = 1, Title = "Snow Black" },
  18:             new Book() { AuthorId = 2, Title = "My Rubber Duckie" },
  19:             new Book() { AuthorId = 2, Title = "He Who Doesn't Know His Name" },
  20:             new Book() { AuthorId = 1, Title = "Hanzel and Brittle" }
  21:         };
  22: 
  23:         var result = from a in authors                              
  24:                      join b in books on a.AuthorId equals b.AuthorId
  25:                      select new { a.Name, b.Title };                
  26: 
  27:         foreach (var r in result)
  28:         {
  29:             Console.WriteLine("{0} - {1}", r.Name, r.Title);
  30:         }
  31:     }
  32: }
John Smith - Little Blue Riding Hood
John Smith - Snow Black
John Smith - Hanzel and Brittle
Harry Gold - My Rubber Duckie
Harry Gold - He Who Doesn't Know His Name
Ronald Schwimmer - The Three Little Piggy Banks

در خطوط 23-25 از یک عبارت join استفاده شده است. عبارت پرس و جو ابتدا یک شیء مؤلف را از منبع داده‌ی خارجی که همان Authors است می‌گیرد، سپس در عبارت join یک شیء کتاب را از منبع داده‌ی داخلی که همان Books است انتخاب می‌کند در نهایت مقدار خاصیت AuthorId از هر دو شیء انتخاب شده را از لحاظ یکسان بودن با هم مقایسه می‌کند .
به این نکته توجه کنید که از کلمه کلیدی equal به جای عملگر == استفاده شده است. عبارت join فقط از لحاظ تساوی دو شیء را مقایسه می‌کند. شما نمی‌تواند از عملگرهایی مانند > یا > برای مقایسه کلیدها استفاده کنید. بنابراین مایکروسافت برای یادآوری این نکته کلمه کلیدی equals را به وجود آورده است.
اگر خاصیت AuthoId کتاب با AuthorId مؤلف برابر باشد، می‌توانید با استفاده از عبارت select نام مؤلف و عنوان کتاب را ترکیب کنید و در نتیجه پرس و جو قرار دهید. هر کتاب با تمامی مؤلف‌ها مقایسه می‌شود و با آنهایی که نظیر باشد (تعلق داشته باشد) در نتیجه پرس و جو قرار می‌گیرد. به این نکته توجه کنید که مولفی با نام Jerry Mawler در نتیجه پرس وجو قرار نمی‌گیرد زیرا دارای کتابی در منبع داده‌ی داخلی وجود ندارد که با آن ترکیب شود. همچنین هر کتابی که آیتم نظیری نداشته باشد در نتیجه پرس وجو قرار نمی‌گیرد. عبارت join مانند سایر عبارات در طی عملیات کامپایل به شکل متدی خود تبدیل می‌شود. عبارت پرس وجوی موجود در مثال بالا را می‌تواند به شکل زیر نوشت :

var result = authors.Join(books, 
                          author => author.AuthorId, 
                          book => book.AuthorId, 
                          (author, book) => new { author.Name, book.Title }
                         );

این نسخه از متد Join نقش یک inner join را بازی می‌کند. این متد چهار پارامتر قبول می‌کند. اولین پارامتر منبع داده داخلی که در اینجا Books است، می‌باشد. دومین پارامتر یک عبارت لامبدا که شامل همه آیتم‌های منبع داده خارجی همراه با کلیدی است که هر آیتم از منبع داده خارجی بر اساس آن با آیتم نظیر خود در منبع داده داخلی ترکیب می‌شود (در این مثال AuthorId به عنوان کلید به کار رفته است). سومین پارامتر هم یک عبارت لامبدا که شامل همه آیتم‌های منبع داده داخلی همراه با کلیدی که با کلید منبع داده خارجی مقایسه می‌شود، می‌باشد. و در نهایت چهارمین پارامتر، گه عبارت لامبدایی با دو پارامتر است، یکی آیتم خارجی و دیگری آیتم داخلی که دارای کلیدهای یکسانی هستند و نتیجه نهایی از ترکیب این دو آیتم می‌باشد.