PDA

View Full Version : آموزش: مقدمه ایی بر آشنایی با Language-Integrated Query یا همان Linq



alimanam
سه شنبه 11 مهر 1391, 23:32 عصر
با سلام

من سعی میکنم در حد چند پست دوستان عزیزی که دوست دارن از تکنولوژی Linq در برنامه هاشون استفاده کنن , اما از اسمش به دلیل ناآشنایی وحشت دارن ! این تاپیک رو به جلو ببرم .

بوسیله Linq میشه خیلی راحت ( بسیار شبیه با اسکریپ های SQL ) در بین انبوهی از داده ها جستجو و فیلترینگ کرد . جالبی Linq این هست که متکی به زبان خاصی نیست و هر زبانی که از این تکنولوژی پشتیبانی کنه میتونه از امکاناتش استفاده کنه . Linq میتونه با انواع پایگاه های داده ایی ,
آرایه ها , فایل های XML و به صورت کلی با هر نوع منبع داده ی رابطه ایی ارتباط برقرار کنه .

LINQ عمل خودش رو از یک سری عملگرهای پرس و جو که بوسیله توابع توسعه , پیاده سازی شده هستن ، بدست میاره این عملگرهای پرس و جو بر روی اشیائی که رابطه های IEnumerable و IQueryable را پیاده سازی کرده باشند، اعمال میکنه .

خوب قبل از اینکه از این کلمات قلمبه گیجتون کنم بریم سر اصل ماجرا که بسیار ساده گفته میشه و به مرور کمی کئوری های پیچیده تری رو توضیح میدم .

در اولین گام یک پروژه جدید اضافه کنید ( از نوع windows forms application یا کنسول application )

لازم به یاد آوری هستش که تکنولوژی Ling از نسخه 3 به بعد فرم ورک اضافه شده پس پروژه ایی که ایجاد میکنین حتماً باید از نسخه 3 به بالای فرم ورک استفاده کنه .

در ابتدا فضای نام زیر رو در محیط کد نویسی به کلاس اصلی فرم برنامه اضافه کنید

Imports System.linq

درادامه , یک کلاس عمومی که دارای چند متغییر ساده است پیاده سازی میکنیم . قراره از این کلاس ( کلاس Person ) در ادامه کار استفاده کنیم .


Partial Friend Class Person
Public [Name] As String
Public Family As String
Public Age As Integer
End Class


خوب همانطور که میبینین کلاس Person سه تا , متغییر عمومی به نام های Name , Family , Age داره که فکر نمیکنم نیاز به توضیح اضافه ایی داشته باشن .

در ادامه کار میائیم یک آبجکت به صورت آرایه که از کلاس Person مشتق شده , میسازیم و به این آبجکت مقادیر دلخواهی رو نسبت میدیم .

Private persons As Person() = New Person() { _
New Person() With {.Name = "Ali", .Family = "Hoseini", .Age = 19}, _
New Person() With {.Name = "Reza", .Family = "Majidi", .Age = 14}, _
New Person() With {.Name = "Mohammad", .Family = "Baghernia", .Age = 30}, _
New Person() With {.Name = "Ahmad", .Family = "Jamilzadeh", .Age = 27}, _
New Person() With {.Name = "Kambiz", .Family = "Mirzaei", .Age = 16}, _
New Person() With {.Name = "Maryam", .Family = "Mohammadi", .Age = 20}, _
New Person() With {.Name = "Reza", .Family = "Karimi", .Age = 15}, _
New Person() With {.Name = "Majid", .Family = "Porrang", .Age = 25}}


خوب الان بر روی فرم اصلی برنامه یک کنترل ListBox اضافه کنید . ( این کنترل برای نمایش اطلاعاتی که قراره بوسیله Linq مورد جستجو قرار میگیره استفاده میشه . یعنی عمل جستجو بوسیله Linq بر روی آبجکت persons که ایجاد کردیم انجام میشه )

حالا یک کنترل Bottun به فرم اضافه کنید و کدهای زیر رو در رویداد کلیک اش بنویسین .


Dim lpersons = From d In persons Where d.Family.StartsWith("M") AndAlso d.Age > 16 Select d
For Each item In lpersons
ListBox1.Items.Add(item.Name & " " & item.Family & " - " & item.Age)
Next


در خط اول کد بالا مشاهد میشه که کدهای استفاده شده بسیار شبیه کدهای اسکریپتی sql هستش ! به اعمال شرط توجه کنین . در ابتدا بوسیله کلمه کلیدی From متغییری به نام d که خودش بوسیله کلمه کلیدی In از آیتم های آبجکت persons مشتق شده معرفی کردیم در ادامه بوسیله کلمه کلیدی Where شرط دلخواهی که همان فامیلی که با کاراکتر "M" شروع میشن رو جستجو میکنه . البته اگه دقت کرده باشین من یک شرط دیگه هم به این کئوری اضافه کردم یعنی بوسیله کلمه کلیدی AndAlso به شرط قبلی این شرط رو اضافه کردم که فردی که دارم جستجوش میکنم سنش باید از 16 بیشتر باشه ! در انتها این کئوری رو انتخاب کرده و نتیجه رو در آرایه Ipersons میریزیم .

خط های بعدی هم که کاملاً واضح و روشنه .

کدهای برنامه فوق :

Imports System.linq
Public Class Form1
Partial Friend Class Person
Public [Name] As String
Public Family As String
Public Age As Integer
End Class
Private persons As Person() = New Person() { _
New Person() With {.Name = "Ali", .Family = "Hoseini", .Age = 19}, _
New Person() With {.Name = "Reza", .Family = "Majidi", .Age = 14}, _
New Person() With {.Name = "Mohammad", .Family = "Baghernia", .Age = 30}, _
New Person() With {.Name = "Ahmad", .Family = "Jamilzadeh", .Age = 27}, _
New Person() With {.Name = "Kambiz", .Family = "Mirzaei", .Age = 16}, _
New Person() With {.Name = "Maryam", .Family = "Mohammadi", .Age = 20}, _
New Person() With {.Name = "Reza", .Family = "Karimi", .Age = 15}, _
New Person() With {.Name = "Majid", .Family = "Porrang", .Age = 25}}

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim lpersons = From d In persons Where d.Family.StartsWith("M") AndAlso d.Age > 16 Select d
For Each item In lpersons
ListBox1.Items.Add(item.Name & " " & item.Family & " - " & item.Age)
Next
End Sub
End Class



من در ادامه تاپیک سعی میکنم با مثال های متعددی که درباره Linq میشه زد شما رو با این تکنولوژی مفید بیشتر آشنا کنم .

موفق باشید./

alimanam
چهارشنبه 12 مهر 1391, 21:05 عصر
با سلام

در پست دوم این تاپیک یک کئوری پیشرفته تر رو با Linq براتون توضیح میدم امیدوارم که به دردتون بخوره . البته ظاهراً کسی این تاپیک رو دنبال نمیکنه به هر حال یه نفر هم به دردش بخوره واسه من کافیه .

در ابتدا مثل پست قبلی یک کلاس جهت استفاده برنامه مینویسیم . ( کلاس Order )


Partial Friend Class Order
Public ID As Integer
Public OrderDate As Date
Public Price As Integer
End Class


در ادامه مقادیری به این کلاس اختصاص میدیم ( از این منابع در ادامه بحث استفاده میشه )


Private Orders As Order() = New Order() { _
New Order() With {.ID = 1, .OrderDate = CDate("01/15/2012"), .Price = 5000}, _
New Order() With {.ID = 2, .OrderDate = CDate("02/14/2011"), .Price = 34000}, _
New Order() With {.ID = 4, .OrderDate = CDate("01/12/2010"), .Price = 3500}, _
New Order() With {.ID = 8, .OrderDate = CDate("03/08/2012"), .Price = 45300}, _
New Order() With {.ID = 1, .OrderDate = CDate("12/30/2009"), .Price = 20000}, _
New Order() With {.ID = 7, .OrderDate = CDate("12/25/2012"), .Price = 15000}, _
New Order() With {.ID = 2, .OrderDate = CDate("09/19/2011"), .Price = 12500}, _
New Order() With {.ID = 1, .OrderDate = CDate("08/15/2012"), .Price = 6000}, _
New Order() With {.ID = 4, .OrderDate = CDate("06/24/2010"), .Price = 6000}, _
New Order() With {.ID = 1, .OrderDate = CDate("05/24/2010"), .Price = 6000}, _
New Order() With {.ID = 5, .OrderDate = CDate("04/10/2010"), .Price = 6000}, _
New Order() With {.ID = 7, .OrderDate = CDate("04/20/2011"), .Price = 6000}}


با نگاهی به اطلاعات بالا مشخص میشه که مشخصات و ویژگیهای کلاس Order چی هست .

خوب به قسمت جالب مسئله میرسیم .

کئوری که در ادامه استفاده میشه به این صورت هست که ما میایم با توجه به ID هر خرید ( هر رکورد کلاس Order یه ID داره که این ID متعلق به یک مشتری هستش به نوعی تاریخچه خرید مشتری های یک فروشگاه میتونه باشه ) مجموع مبلغ خریدهای هر آی دی رو استخراج میکنیم . به اصطلاح با استفاده از عملگر Gorup این کار صورت میگیره .


Dim totalPrices = From order In Orders _
Group order By order.ID _
Into TotalPrice = Sum(order.Price) Order By ID


همانطور که مشاهده میشه عملگرد Group با توجه به فیلدی که براش تعیین کردیم ( در اینجا فیلد ID کلاس Order ) خرید های هر مشتری رو دسته بندی میکنه و در ادامه با استفاده از عملگر Sum مجموع این دسته ها رو به دست میاره . در انتها بر اساس ID اطلاعات استخراج شده رو با استفاده از عملگر Order By اونها رو Sort ( از کوچک به بزرگ دسته بندی میکنه )

برای نمایش اطلاعات دسته بندی شده ( مجموع خریدهای هر مشتری ) از کدهای زیر استفاده میکنم :


For Each item In totalPrices
TextBox1.Text &= ("ID : " & item.ID & " ---> " & item.TotalPrice) & vbCrLf
Next


بعد از اعمال کئوری نتایج زیر به دست میاد :


ID : 1 ---> 37000
ID : 2 ---> 46500
ID : 4 ---> 9500
ID : 5 ---> 6000
ID : 7 ---> 21000
ID : 8 ---> 45300


کدهای استفاده شده :


Imports System.Linq
Public Class Form1

Partial Friend Class Order
Public ID As Integer
Public OrderDate As Date
Public Price As Integer
End Class

Private Orders As Order() = New Order() { _
New Order() With {.ID = 1, .OrderDate = CDate("01/15/2012"), .Price = 5000}, _
New Order() With {.ID = 2, .OrderDate = CDate("02/14/2011"), .Price = 34000}, _
New Order() With {.ID = 4, .OrderDate = CDate("01/12/2010"), .Price = 3500}, _
New Order() With {.ID = 8, .OrderDate = CDate("03/08/2012"), .Price = 45300}, _
New Order() With {.ID = 1, .OrderDate = CDate("12/30/2009"), .Price = 20000}, _
New Order() With {.ID = 7, .OrderDate = CDate("12/25/2012"), .Price = 15000}, _
New Order() With {.ID = 2, .OrderDate = CDate("09/19/2011"), .Price = 12500}, _
New Order() With {.ID = 1, .OrderDate = CDate("08/15/2012"), .Price = 6000}, _
New Order() With {.ID = 4, .OrderDate = CDate("06/24/2010"), .Price = 6000}, _
New Order() With {.ID = 1, .OrderDate = CDate("05/24/2010"), .Price = 6000}, _
New Order() With {.ID = 5, .OrderDate = CDate("04/10/2010"), .Price = 6000}, _
New Order() With {.ID = 7, .OrderDate = CDate("04/20/2011"), .Price = 6000}}

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

Dim totalPrices = From order In Orders _
Group order By order.ID _
Into TotalPrice = Sum(order.Price) Order By ID

For Each item In totalPrices
txtResulte.Text &= ("ID : " & item.ID & " ---> " & item.TotalPrice) & vbCrLf
Next

End Sub

End Class


موفق باشید./

Hybrid
چهارشنبه 12 مهر 1391, 23:11 عصر
سلام دوستان ، با تشکر از دوست عزیزم علی جان که این تاپیک مفید رو ایجاد کردن ، با اجازه علی جان من هم یک مثال میزنم ؛

شما میتونید با استفاده از عملگر Let یک متغیر موقت در درون Linq ، Query درست کنید و در محاسبات بعدی به راحتی ازش استفاده کنید ، .

کلمه کلیدی Let :

Linq یک کلمه کلیدی خیلی جالب داره که به شما امکان میده در درون query هاتون یک متغیر موقت درست کنید ؛ مثلا میتونید نتیجه ی محاسباتی که در داخل Query انجام میدین در داخل این متغیر موقت قرار بدین و در عملیات های بعدیتون به راحتی ازش استفاده کنید.

نحوه ی استفاده از این کلمه کلیدی :

2 تا آرایه از نوع Integer و به نام های FirstArray و SecondArray ایجادکنید :

Dim Arrayfirst As Integer() = New Integer() {1, 2, 3}
Dim Arraysecond As Integer() = New Integer() {1, 2, 3}
الان با استفاده از Linq میخوایم حاصل ضرب اعضای این مجموعه رو در همدیگه ( ضرب دکارتی) که بزرگتر از 4 باشند رو بدست بیاریم ؛ کافیه از Query به شکل زیر استفاده کنیم :

Dim Squares = From Queryfirst In Arrayfirst From Querysecond In Arraysecond Let _
TheSquare = Queryfirst * Querysecond Where TheSquare > 4 Select Queryfirst, Querysecond, TheSquare

نگاهی کامل به مثال : یک پروژه از نوع Console Application ایجاد کنید ( به فریمورک برنامه دقت کنید که از 3 بالاتر باشه) سپس کد زیر رو داخل بدنه اصلی برنامه کپی کنید :


Dim Arrayfirst As Integer() = New Integer() {1, 2, 3}
Dim Arraysecond As Integer() = New Integer() {1, 2, 3}
Dim Squares = From Queryfirst In Arrayfirst From Querysecond In Arraysecond Let _
TheSquare = Queryfirst * Querysecond
Where TheSquare > 4 Select Queryfirst, Querysecond, TheSquare
For Each ThisSquare In Squares
Console.WriteLine(ThisSquare.TheSquare.ToString())
Next
Console.ReadLine()

موفق باشید./

Hybrid
پنج شنبه 13 مهر 1391, 22:44 عصر
سلام دوباره خدمت دوستان عزیز ، در این آموزش میخوام نحوه ی مقایسه کردن 2 دنباله از مقادیر رو به وسیله Linq بدم امیدوارم مفید باشه ،

شما به راحتی میتونید این کار رو به وسیله Enumerable.SequenceEqual() (http://msdn.microsoft.com/en-us/library/bb348567.aspx) انجام بدین ، این متد ( SequenceEqual ) اعضای 2 دنباله رو تک به تک با هم مقایسه میکنه و یک مقدار Boolean رو واستون برگشت میده به مثال زیر دقت کنید :

مثال ) یک پروژه از نوع Console Application با فریمورک 3 به بالا درست کنید و کد زیر رو داخل بدنه اصلی برنامه بنویسید :


Dim l1 As Integer() = New Integer() {1, 2, 3, 4, 5, 6, 7, 8, 9}
Dim l2 As Integer() = New Integer() {1, 2, 3, 4, 5, 6, 7, 8}

Dim result As Boolean = l1.SequenceEqual(l2)
Console.Write("Are they Equals : ")

If result Then
Console.WriteLine("True")
Else
Console.WriteLine("False")
Console.WriteLine("Difference between two Sequences : ")

Dim s1 = l1.Except(l2)
For Each counter In s1
Console.WriteLine(counter)
Next

End If
Console.ReadLine()

** کد بالا 2 آرایه از اعداد صحیح ایجاد میکنه و از طریق متد SequenceEquals اعضای 2 آرایه تک به تک باهم مقایسه میکنه و نتیجه بازگشتی ( که True یا False ) هست رو در متغیر بولی result قرار میده ، در دنباله کد چک میکنه که اگه متغیر Result دارای مقدار False باشه اختلاف اعضای 2 آرایه که عضو 9 هست را به وسیله ی متد Except به دست میاره و در خروجی چاپ میکنه .

http://eupm.vpsq.net/images/ea3f1874b188.jpg

Hybrid
پنج شنبه 13 مهر 1391, 23:01 عصر
سلام ،

حتما میدونید که حلقه For Each چه کاری رو انجام میده این حلقه جهت گردش در یک مجموعه به کار میره به این طریق که در هر بار گردش حلقه به ترتیب تک تک تعضا در شمارنده حلقه قرار میگیره ، خب بعضی مواقع نیاز دارید این اعضا رو فیلتر کنید مثلا یک مجموعه دارید شامل اعضای 100- تا 100 ولی شما میخواین که از 0 تا 100 رو داخل شمارنده حلقه بزارید و دیگه کاری با 100- تا 0 نداشته باشید ، میتونید به راحتی با استفاده از Linq این کار رو انجام بدین ،

فیلتر کردن اعضا یک مجموعه در حلقه For Each :

مثال ) یک پروژه Console Application ایجاد کنید(به فریمورک برنامه دقت کنید) ، سپس کد زیر رو داخل بدنه اصلی برنامه بنویسید و نتیجه رو مشاهده کنید :


Dim arr As ArrayList = New ArrayList()
With arr
.Add(1)
.Add(2)
.Add(10)
.Add(12)
.Add(13)
End With

For Each counter In arr.OfType(Of Integer).Where(Function(x) x >= 10)
Console.WriteLine(counter)
Next

Console.ReadLine()

** کد بالا یک لیست ارایه ای ایجاد میکنه و بعضی از مقادیر رو به کمک متد Add به لیست آرایه ای اضافه میکنه ، در ادامه اومدیم با استفاده از حلقه For Each اعضا این آرایه رو که از 10 بزرگتر هستند ( با احتساب 10) در خروجی چاپ کردیم ، به زبان ساده در اعلان حلقه اومدیم یک شرط رو قرار دادیم که این شرط لیست آرایه ای رو به 2 قسمت تقسیم میکنه و اومدیم با قسمت دوم که بزرگتر و مساوی با 10 هست کار کردیم و اونا رو در خروجی چاپ کردیم ،

مثال 2 ) کد زیر بهتون نشون میده که چطوری با استفاده از Linq میتونید اعضای رشته ای یک لیست آرایه ای رو بدست بیارین :


Dim arr As ArrayList = New ArrayList From {"siavash", 100, "soroush", False, "Sara"}
Dim StringElements = arr.OfType(Of String)()

For Each counter In StringElements
Console.WriteLine(counter)
Next

Console.ReadLine()