LINQ to SQL یک بستر Object-Relational Mapping ایجاد می کند که اجازه می دهد یک mapping یک به یک بین MS SQL و کلاس های دات نت ایجاد شود . به طور خلاصه LINQ to SQL برای نرم افزارهایی که به روش Rapid Development پیاده سازی می شوند و احتیاج به کار و استفاده از بانک اطلاعاتی دارند بسیار مفید و باعث تسهیل در کار با بانک اطلاعاتی می شود . در این مدل امکان پرس و جو از بانک اطلاعاتی ، افزودن ، حذف و ویرایش اطلاعات به راحتی فراهم است . عملیات کار با بانک اطلاعاتی بوسیله ترجمه پرس و جوهای language integrated به sql برای اجرا در بانک اطلاعاتی و سپس ترجمه خروجی SQL به آبجکت های داخل زبان برنامه نویسی انجام می شود .

 


DataContext مجرای اصلی دریافت اطلاعات از بانک اطلاعاتی و فرستادن تغییرات به آن است . روش استفاده از آن به همان روشی است که در ADO.NET از Connection استفاده می کردید . هدف استفاده از DataContext ترجمه درخواست هایی است که به آبجکت ها می رسد به زبان SQL ، سپس ترجمه جواب بانک اطلاعاتی به Object ها . DataContext اجازه می دهد عملگرهایی که در LINQ استفاده می کنیم مشابه عملگرهای استاندارد SQL شوند ، مانند Where  . برای استفاده از DataContext به روش ADO.NET Connection می بایست آدرس فایل بانک اطلاعاتی را به آن فرستاد . روش دیگر استفاده از بخشی است که در Visual Studio برای این کار فراهم شده و بسیار ساده تر از روش دستی است .

 


برای ادامه احتیاج به یک بانک اطلاعاتی داریم . لذا با بانکی ساده شامل جداولی که اطلاعات محصولات و گروه بندی آنها ، مشتریان و خرید آنها را نگهداری می کند شروع می کنیم . در شکل زیر دیاگرام جداول را مشاهده می کنید .


 

 

جداول بالا حاوی اطلاعات زیر است :
جدول گروه بندی محصولات


 

 

جدول محصولات

 

 

جدول مشتریان

 

 

سپس در Visual Studio در قسمت Server Explorer در Data Connections یک اتصال جدید به بانک اطلاعاتی ایجاد می کنیم .

 

 

وقتی بانک اطلاعاتی به لیست اضافه شد امکان مشاهده جداول آن فراهم می شود .

 

 

حالا در Solution Explorer روی نام پروژه کلیک سمت راست را زده و یک فایل LINQ to SQL Classes با نام ProductSales ایجاد می کنیم .

 

 

در Solution Explorer روی ProductSales.dbml دبل کلیک می کنیم تا باز شود . سپس هر یک از جداولی که در Connection جدید وجود دارد را به شکل drag and drop  روی فایل dbml قرار می دهیم .

 

 

شکل بالا دیاگرام mappingی است که کلاس های مورد نیاز در نرم افزار از بانک اطلاعاتی ایجاد شده. اگر توجه کنید نام جداول نسبت به بانک اطلاعاتی کمی تغییر کرده. نام ها در بانک اطلاعاتی به شکل جمع انگلیسی بود ولی در اینجا به شکل جمع نیست . این سبک در نام ها هنگام به کار گیری کلاس ها از ابهام آنها جلوگیری می کند . البته با دبل کلیک بر روی هر کدام از نام ها امکان تغییر آن وجود دارد . درباره property های این کلاسها در dbml در پست های بعدی مطالبی خواهید خواند .


بر روی یک فرم ، یک DataGridView و یک button قرار می دهیم مانند شکل زیر :


 

 

در رویداد Click در Button کد زیر را می نویسیم .

Dim db As New ProductSalesDataContext

Dim ProCats = From pc In db.ProductCategories _

Select pc

DataGridView1.DataSource = ProCats

 

ProductSalesDataContext db = new ProductSalesDataContext();

var ProCats = from pc in db.ProductCategories

select pc;

dataGridView1.DataSource = ProCats;

خط اول یک نمونه از DataContext می سازد . در خط بعدی تمامی رکوردهای موجود در جدول ProductCategories  را از بانک اطلاعاتی می خواند .


این ساده ترین شکل استفاده از LINQ to SQL است.

 

 

حالا یک button جدید با نام افزودن به فرم اضافه کرده و در رویداد Click آن کد زیر را می نویسیم .

Dim db As New ProductSalesDataContext

Dim pc As New ProductCategory With {.Name = "cat 1"}

db.ProductCategories.InsertOnSubmit(pc)

db.SubmitChanges()

 

ProductSalesDataContext db = new ProductSalesDataContext();

ProductCategory pc = new ProductCategory { Name = "cat 1"};

db.ProductCategories.InsertOnSubmit(pc);

db.SubmitChanges();

 

اگر دوباره کلید دریافت را بزنیم رکورد جدید نیز نمایش داده می شود .

 


 

در خط اول یک نمونه از DataContext ساخته شده سپس یک ProductCategory می سازیم و آن را به ProductCategories اضافه می کنیم . آن تغییر نام که در نام کلاس ها ایجاد شده بود و از جمع بودن (ProductCategories) خارج شده بود اینجا خود را نمایان می کند .


برای ویرایش یک button دیگر روی فرم اضافه کرده و کد زیر را در آن می نویسیم .

Dim db As New ProductSalesDataContext

Dim pc = (From p In db.ProductCategories Where _

p.Name = "cat 1" _

Select p).SingleOrDefault

If Not pc Is Nothing Then

pc.Name = "Cat 1+1"

db.SubmitChanges()

End If

 

 

ProductSalesDataContext db = new ProductSalesDataContext();

var pc = (from p in db.ProductCategories

where

p.Name == "cat 1"

select p).SingleOrDefault ();

if (pc != null)

{

pc.Name = "Cat 1+1";

db.SubmitChanges();

}

 

در خط دوم سعی می کنیم رکوردی را که نامش cat 1 است را پیدا کنیم . خروجی این درخواست از بانک اطلاعاتی می بایست یک رکورد باشد یا هیچ باشد . اگر cat 1 وجود نداشت هیچ رکوردی بازگردانده نمی شود و اگر وجود داشت فقط یک رکورد لذا از SingleOrDefault استفاده شده است .


در بخش آخر هم اگر رکورد مورد نظر ما وجود داشت مقدار آن را تغییر داده و تغییرات را به بانک اطلاعاتی می فرستیم . اگر دوباره button دریافت را بزنیم اطلاعات جدید نمایش داده می شود


 

 

یک Button دیگر برای حذف به فرم اضافه کرده و کد زیر را در رویداد کلیک آن می نویسیم :

Dim db As New ProductSalesDataContext

Dim pc = (From p In db.ProductCategories Where _

p.Name = "Cat 1+1" _

Select p).SingleOrDefault

If Not pc Is Nothing Then

db.ProductCategories.DeleteOnSubmit(pc)

db.SubmitChanges()

End If

 

 

ProductSalesDataContext db = new ProductSalesDataContext();

var pc = (from p in db.ProductCategories

where

p.Name == "cat 1"

select p).SingleOrDefault ();

if (pc != null)

{

db.ProductCategories.DeleteOnSubmit (pc);

db.SubmitChanges();

}

 

 

تنها تفاوت با ویرایش در خط قبل از Submit است .


حالا یک فرم دیگر به پروژه اضافه کرده و یک کلید و یک DataGridView به آن اضافه می کنیم . در رویداد کلیک برای کلید کد زیر را می نویسیم .

Dim db As New ProductSalesDataContext

Dim Ps = From p In db.Products _

Select p

DataGridView1.DataSource = Ps

 

ProductSalesDataContext db = new ProductSalesDataContext();

var ps = from p in db.Products select p;

dataGridView1.DataSource = ps;

در این کد تمام رکورد های جدول محصولات دریافت می شود ، مانند شکل زیر :

 

 

البته ما نیازی به همه فیلدها نداریم . نام ، هزینه و گروه محصول کافی است . برای این منظور از کد زیر استفاده می کنیم .

Dim db As New ProductSalesDataContext

Dim Ps = From p In db.Products _

Select New With {.Name = p.Name, .Price = p.Price, .CatName = p.ProductCategory.Name}

DataGridView1.DataSource = Ps

 

ProductSalesDataContext db = new ProductSalesDataContext();

var Ps = from p in db.Products select new { Name = p.Name, Price = p.Price, CatName = p.ProductCategory.Name};

dataGridView1.DataSource = Ps;

و شکل زیر خروجی را نمایش می دهد :

 

 

در جدول فروش تعدادی رکورد به روش دستی اضافه کردم که شامل فروش فقط از دو محصول می شود . اگر بخواهیم در کنار لیست محصولات ، فروش آنها را هم ببینیم می توان از کد زیر استفاده کرد .

Dim db As New ProductSalesDataContext

Dim Ps = From p In db.Products _

Select New With {.Name = p.Name, .Price = p.Price, .CatName = p.ProductCategory.Name _

, .Foroosh = Aggregate F In p.Factors Into Sum(New Decimal?(F.Total))}

DataGridView1.DataSource = Ps

 

ProductSalesDataContext db = new ProductSalesDataContext();

var Ps = from p in db.Products select new { Name = p.Name, Price = p.Price, CatName = p.ProductCategory.Name ,

Foroosh = p.Factors.Sum(a => (decimal?)a.Total) };

dataGridView1.DataSource = Ps;

 

 

با توجه به اینکه بین جداول رابطه برقرار است می توانیم مستقیماً فاکتورهایی که به مربوط به هر محصول است را بازیابی کنیم . از تابع Aggregate برای جمع آوری اطلاعات از جدول فاکتورها و قرار دادن آن در فیلد فروش استفاده شده . خروجی این تابع از نوع Decimal? است . Decimal? به این معنی است که یا خروجی Decimal است یا Null . اگر از New Decimal? استفاده نکنیم در زمان اجرا خطا رخ خواهد داد زیرا تعداد زیادی از محصولات فروخته نشده اند و عددی برای جمع قیمت فروش آنها قابل استخراج نیست .


حالا می خواهیم سیمان به یکی از مشتریان بفروشیم ! یک button جدید ایجاد کرده و از کد زیر استفاده می کنیم .

Dim db As New ProductSalesDataContext

Dim p = db.Products.Single(Function(c1) c1.Name = "سیمان")

Dim c = db.Customers.Single(Function(c2) c2.Name = "حامد بنایی")

Dim f As New Factor With {.Customer = c, .Product = p, .Quantity = 1, .Total = p.Price}

db.Factors.InsertOnSubmit(f)

db.SubmitChanges()

 

ProductSalesDataContext db = new ProductSalesDataContext();

var p = db.Products.Single(c1 => c1.Name == "سیمان");

var c = db.Customers.Single(c2 => c2.Name == "حامد بنایی");

Factor f = new Factor {Customer = c , Product = p , Quantity = 1 , Total = p.Price };

db.Factors.InsertOnSubmit(f);

db.SubmitChanges();

از جدول محصولات سیمان را انتخاب کردیم . از جدول مشتریان حامد بنایی انتخاب شده و در جدول فاکتورها اضافه شده اند . اگر ID مربوط به مشتری و محصول را می دانستیم به جای .Customer = c می توانستیم از .CustomerID = 123 که 123 شماره آن مشتری است استفاده کنیم .


نتیجه بعد از اجرای این دستورات :


 

 

البته شاید ما بخواهیم همیشه بیشتر از یک عدد از هر محصول خریداری شود ! یک راهش این است که در کد هنگام افزودن به فاکتور این کار را انجام دهیم . راه دیگر را در کد زیر می بینید .

Partial Public Class Factor

Private Sub OnQuantityChanging(ByVal value As Integer)

If value <= 1 Then

Throw New Exception("Bishtar bekhar")

End If

End Sub

End Class

از آنجایی که تمام جدول های ما به کلاس ها تبدیل شده اند می توان همه را به شکلی که در بالا می بینید تغییر داد . هر کدام از فیلدهای جدول نیز دارای OnChanging هستند که اگر یک خطا در آن برای مقدار نا معتبر رخ دهد همان کاری را خواهد کرد که می خواستیم .


کد های سی شارپ این پست را طی هفته آینده به همین مطلب اضافه می کنم . انواع مثال های مربوط به LINQ را در مطلب جدیدی اضافه خواهم کرد .


منابع : 

http://msdn.microsoft.com/en-us/library/bb425822.aspx
http://msdn.microsoft.com/en-us/library/cc161164.aspx

http://www.asp.net/LEARN/linq-videos

Gravatarکیوان نیّریWwW
پنج شنبه ساعت 22:26 , 30/8/1387
اینجاست که می گویند: مااااااااااا! در ایران عزیز کسی از این جور پستها نگارش نمی کند!

حالا من کجام به لس آنجلس می خوره که اونجا زدین لس آنجلس؟!
GravatarShahoWwW
جمعه ساعت 01:27 , 1/9/1387
سلام ما را از هوای بارانی و مه آلود لندن داشته باشید!
بسیار مرسی، چون تازه الان فهمیدیم که این LINQ یه کارایی انجام میده شبیه Rake db:migrate خودمان در Ruby on Rails
Gravatarآرمین
جمعه ساعت 11:26 , 1/9/1387
جناب مهندس کارت درست هستش
همین طوری ادامه بدهید.
موفق و پیروز باشید.
Gravatarامیر
چهارشنبه ساعت 17:31 , 6/9/1387
سلام
مهندس تو دات نت فریم ورک 4 از LINQ to SQL دیگه استفاده نمی شه!!!!! به جاش باید از LINQ to Entity استفاده کنید.
Gravatarحامد بنايی
پنج شنبه ساعت 11:04 , 7/9/1387
هر موقع نسخه نهايی دات نت 4 آمد می رويم دنبالش !
Gravatarامیر
يکشنبه ساعت 17:36 , 10/9/1387
مهندس وقت کردی ببین Entity FrameWork .Netچیه به ما هم بگو!!! دستت درد نکه جوون!!!
GravataraliWwW
پنج شنبه ساعت 00:27 , 21/9/1387
سلام
مطالب جالبی بود. یه سوال داشتم. چظور میشه در یک Field از نوع Ntext فقط مقدار 50 یا 100 کاراکتر رو برگردوند.
من که هر کاری می کنم کل مقدار موجود در Ntext رو بر میگردونه.
با تشکر
www.bitasoft.ir
Gravatarحامد بنايی
پنج شنبه ساعت 10:11 , 21/9/1387
Dim a = (From s In db.nTextTables Let b = s.nTextField.Substring(1, 5) Select b).SingleOrDefault
البته اگر در حلقه استفاده می کنيد singleorDefault را نمی خواهد.
Gravatarعلي
دوشنبه ساعت 17:36 , 8/4/1388
سلام من يك جدول دارم كه داراي فيلدي از نوع TEXT مي باشد و مي خواهم 50 كاراكتر اول هر ركورد را فقط چاپ كنم چگونه بايد اين كار را انجام هم. اين جدول در MYsql يا Sql مي باشد.
Gravatarحامد بنایی
پنج شنبه ساعت 17:51 , 11/4/1388
در همین نظرها نمونه اش است .
Gravatarjavad
پنج شنبه ساعت 10:19 , 18/12/1390
سلاملطفا در مورد توابع لامبدا نیز توضیح دهیدبا تشکر
نام :   
ايميل :      اين سايت از سيستم گراواتر استفاده می کند ، اگر در گراواتر دارای کد کاربری هستيد می توانيد از آن آدرس ايميل استفاده کنيد.  
وب سايت :   
ديدگاه :   
عدد زير را وارد کنيد :
  


  پيام شما بعد از بازبينی افزوده خواهد شد.