پرس و جو در دیتابیس با استفاده از LINQ to SQL

می‌خواهیم یک برنامه ویندوزی ایجاد کنیم که به شما اجازه پرس و جوی یک رکورد از یک جدول خاص با استفاده از کلاس‌های LINQ to SQL را می‌دهد. شما می‌آموزید که چگونه با استفاده از محیط Object Relational Designer کلاس‌های LINQ to SQL را تولید و از آنها در کدنویسی استفاده کنید.

ایجاد دیتابیس و جدول

قبل از شروع این آموزش، ابتدا یک دیتابیس با یک جدول ایجاد کرده و سپس چندین داده را در داخل جدول وارد می‌کنیم. برای این منظور ابتدا پنجره‌ی Server Explorer را ظاهر می‌کنیم. برای نمایش این پنجره به مسیر Views > Server Explorer بروید. بعد از باز شدن این پنجره بر روی آیکن Connect to database کلیک کنید :
linq-to-sql-01
سپس پنجره‌ای به صورت زیر باز می‌شود که از شما می‌خواهد نام یا مسیر یک دیتابیس را وارد کنید. چون قرار است یک دیتابیس جدید ایجاد کنیم، یک نام برای دیتابیس انتخاب کرده و سپس بر روی دکمه OK کلیک می‌کنیم :
linq-to-sql-02
با کلیک بر روی دکمه OK پیغامی به صورت زیر به نمایش در می‌آید که به شما می‌گوید که این دیتابیس از قبل وجود ندارد، آیا می‌خواهید آن را ایجاد کنید؟ که با زدن بر روی دکمه Yes دیتابیس ما که در اینجا نام آن myDatabase است ایجاد می‌شود :
linq-to-sql-03
بعد از ایجاد دیتابیس، مانند شکل زیر، بر روی یکی از زیر پوشه‌های آن به نام Tabels راست کلیک کرده و گزینه Add New Table را می‌فشاریم :
linq-to-sql-04
با کلیک بر روی گزینه مذکور صفحه‌ای به صورت زیر به نمایش در می‌آید که شما در این صفحه نام ستون‌های جدول را انتخاب کرده (1)، نام جدول را به Persons تغییر داده (2) و سپس بر روی دکمه Update کلیک کنید :
linq-to-sql-05
با کلیک بر روی دکمه Update پنجره‌ای به صورت زیر ظاهر می‌شود که بعد از زدن دکمه Update Database پیغامی مبنی بر موفقیت آمیز بود ایجاد جدول به شما نمایش داده می‌شود :
linq-to-sql-06

linq-to-sql-07
حال اگر به پنجره Server Explorer نگاه کنید، مشاهده می‌کنید که یک جدول به نام Persons به دیتابیس myDatabase اضافه شده است :
linq-to-sql-08
بعد از ایجاد جدول نوبت به اضافه کردن داده‌ها به جدول مذکور می‌رسد، به صورت زیر بر روی نام جدول راست کلیک و سپس بر روی گزینه Show Table Data کلیک کیند :
linq-to-sql-09
و در نهایت در زیر ستون‌های مربوطه داده‌های مورد نظرتان را وارد کنید :
linq-to-sql-10

ایجاد کلاس‌های LINQ to SQL

یک برنامه ویندوزی ایجاد کرده و نام آن را LinqToSqlDemo بگذارید. وقتی که پروژه ایجاد شد، لازم است که یک فایل LINQ to SQL به آن اضافه کنیم. به صورت زیر بر روی نام پروژه راست کلیک کرده و گزینه Add و سپس New Item را بفشارید. سپس از صفحه باز شده گزینه LINQ to SQL Classes را انتخاب و نام آن را Sample گذاشته و بر روی دکمه Add کلیک کنید.

linq-to-sql-11

linq-to-sql-12
وقتی که بر روی دکمه Add کلیک کنید محیط Object Relational Designer ظاهر می‌شود.
linq-to-sql-13
اکنون ToolBox شامل ابزارهایی برای ایجاد کلاس‌ها و ارتباط بین آن‌ها می‌باشد. اما از آن جاییکه ما می‌خواهیم کلاس‌ها را با استفاده از یک جدول موجود در دیتابیس ایجاد کنیم، فعلاً از این ابزارها استفاده نمی‌کنیم. یک فایل DBML یا Database Markup Language با پسوند dbml. در Solution Explorer ایجاد و نمایش داده می‌شود. بر روی فلش کنار این فایل کلیک کرده تا فایل‌های زیر مجموعه آن نمایش داده شوند. بر روی فایل با پسوند DBML دوبار کلیک کرده تا Object Relational Desinger برای شما نمایش داده شود:
linq-to-sql-14

حال می‌خواهیم دیتایبس myDatabase را به پنجره‌ی Server Explorer اضافه نماییم. بر روی فلش کنار آن کلیک کرده تا زیر پوشه‌های این دیتابیس نمایش داده شوند، یکی از این پوشه‌ها Tables است که لیست تمامی جداول دیتایبس در آن قرار دارد. حال که تمامی جداول نمایش داده شدند، لازم است که جداول دلخواه را به محیط Object Relational Designer با ماوس بکشیم (Drag & Drop). در این درس ما جدول Persons را به این محیط می‌کشیم.
linq-to-sql-15

با کشیدن جدول به محیط Object Relational Designer پیغامی به شما نمایش داده می‌شود مبنی بر اینکه فایل دیتابیس در پوشه‌ی پروژه‌ی شما وجود ندارد، آیا مایل هستید که یکی نسخه (کپی) به پوشه پروژه انتقال داده شود؟ بر روی دکمه‌ی Yes کلیک کنید.

linq-to-sql-16
بعد از زدن دکمه‌ی Yes، به ازای هر جدول کشیده شده به محیط (مثلاً در اینجا Persons) یک کلاس همنام اما به صورت مفرد ایجاد می‌شود (مثلاً نام Persons به Person تبدیل می‌شود) و به ازای هر فیلد در جدول کشیده شده، یک خاصیت هم نام و با نوع سازگار در آن ایجاد می‌شود (به عنوان مثال نوع سازگار با nvarchar در دات نت string می‌باشد). در کل مهمترین نکنه در مورد LINQ to SQL همین است که :

linq-to-sql-17
همانطور که در شکل بالا مشاهده می‌کنید، اسم جدول به Person و نوع PersonID به int تغییر داده می‌شود. حال فرض کنید که یک فیلد به نام Person در جدول موجود باشد. در این صورت اگر جدول را به محیط Object Relational Designer بکشید یک تداخل به وجود می‌آید (بین اسم کلاس و اسم خصوصیت که هر دو Person می‌شود). برای حل این مشکل Visual Studio یک شماره به انتهای نام خصوصیت اضافه می‌کند. در این مثال اسم خصوصیت به Person1 تغییر داده می‌شود .
وقتی که جدول را به Object Relational Designer می‌کشیم، یک کلاس با پسوند DataContext ایجاد می‌شود. نامگذاری آن هم به این صورت است که قبل از نام این کلاس، نامی که برای کلاس LINQToSQL انتخاب کرده‌ایم، می‌آید. مثلاً در مثال بالا چون ما موقع ایجاد کلاس‌های LINQToSQL نام Sample را انتخاب کردیم، در نتیجه کلاسی به نام SampleDataContext ایجاد می‌شود. با کلیک بر روی یک فضای خالی از Object Relational Designer به شما اجازه ویرایش خاصیت‌های کلاس DataContext با استفاده از پنجره Properties داده می‌شود. شما همچنین می‌توانید خواص کلاس سطر ایجاد شده و خواص اعضای آن را تغییر دهید. اما پیشنهاد می‌شود این نام‌ها و تنظیمات پیشفرض را تغییر ندهید.
اما اگر در مورد نحوه تولید کلاس‌ها کنجکاو هستید و می‌خواهید به نحوه پیاده سازی آنها نگاهی بیندازید به پنجره Solution Explorer رفته و بر روی فلش کنار فایل DBML ایجاد شده کلیک کنید. با اینکار دو فایل زیر مجموعه برای شما نمایش داده می‌شود. بر روی فایلی که پسوند آن .designer.cs دو بار کلیک کنید. با این کار، کلاس‌های جداول و کلاس DataContext برای شما نمایش داده می‌شوند. شما باید قبل از استفاده از فایل DBML آن را ذخیره کنید.

استفاده از کلاس‌های LINQ to SQL

وقتی که کلاس‌های LINQ to SQL با موفقیت تولید شدند می‌توانید از آنها در برنامه‌تان استفاده کنید. در این برنامه ما می‌خواهیم به طور ساده و فقط با استفاده از یک کنترل DataGridView نتایج پرس و جو را نمایش دهیم. به محیط طراحی رفته و یک کنترل DataGridView بر روی فرم و خاصیت Dock آن را بر روی Fill قرار دهید تا کل فضای فرم را در بر بگیرد. سپس فرم را به اندازه‌ای بزرگ کنید که کل نتایج پرس و جو را بتوان در دیتاگریدویو نمایش داد. سپس بر روی فرم دو بار کلیک کرده و کد زیر را در رویداد Load فرم بنویسید :

   1: using System;
   2: using System.Data;
   3: using System.Linq;
   4: using System.Windows.Forms;
   5: 
   6: namespace LinqToSqlDemo
   7: {
   8:     public partial class Form1 : Form
   9:     {
  10:         public Form1()
  11:         {
  12:             InitializeComponent();
  13:         }
  14: 
  15:         private void Form1_Load(object sender, EventArgs e)
  16:         {
  17:             SampleDataContext database = new SampleDataContext();
  18: 
  19:             var allPersons = from person in database.Persons
  20:                           select new
  21:                           {
  22:                               person.PersonID,
  23:                               person.FirstName,
  24:                               person.LastName,
  25:                               person.Age
  26:                           };
  27: 
  28:             dataGridView1.DataSource = allPersons;
  29:         }
  30:     }
  31: }

با دو بار کلیک بر روی عنوان فرم در محیط طراحی رویداد Load تولید می‌شود. سپس خطوط 28-17 را به آن اضافه کنید. در خط 17 یک شیء از SampleDataContext ایجاد کرده‌ایم. با این کار دسترسی به جداول دیتابیس و سطرهای آن امکان پذیر می‌شود. در خطوط 26-19 با استفاده از یک کوئری Linq به تمامی رکوردهای جدول از طریق خصوصیت Persons مربوط به SampleDataContext دسترسی پیدا می‌کنیم. از طریق دستور select فقط چند خاصیت را انتخاب کرده‌ایم. و در نهایت در خط 28 نتیجه را در خاصیت Datasource از کنترل Datagridview قرار داده‌ایم که این کار باعث نمایش داده‌ها در این کنترل می‌شود. با اجرای برنامه تمام رکوردهای جدول Persons را مشاهده خواهید کرد.
linq-to-sql-18
در خطوط 26-19 با استفاده از یک کوئری ساده Linq برخی از فیلدهای جدول Persons را انتخاب و نمایش دادیم. شما می‌توانید بسته به نیاز خود کوئری های مختلفی را بنویسید. به عنوان مثال می‌توانیم کوئری خطوط 26-19 را به شکلی تغییر دهیم که فقط افرادی که 17 سال سن دارند نمایش داده شوند :

var allPersons = from person in database.Persons
                where person.Age == 17
                select new
                {
                    person.PersonID,
                    person.FirstName,
                    person.LastName,
                    person.Age
                };