linq Handledning
Komma igång med linq
Sök…
Anmärkningar
LINQ är en uppsättning funktioner som introduceras i .NET Framework version 3.5 som överbryggar klyftan mellan objektens värld och datavärlden.
Traditionellt uttrycks frågor mot data som enkla strängar utan typkontroll vid sammanställningstid eller IntelliSense-support. Dessutom måste du lära dig ett annat frågespråk för varje typ av datakälla: SQL-databaser, XML-dokument, olika webbtjänster och så vidare. LINQ gör en fråga till en förstklassig språkkonstruktion i C # och Visual Basic. Du skriver frågor mot starkt typade samlingar av objekt med hjälp av språkord och kända operatörer.
Uppstart
LINQ kräver. NET 3.5 eller högre (eller .NET 2.0 med LINQBridge ).
Lägg till en referens till System.Core , om den inte har lagts till ännu.
Överst i filen, importera namnområdet:
- C #
using System;
using System.Linq;
- VB.NET
Imports System.Linq
De olika går med i LINQ
I följande exempel använder vi följande prover:
List<Product> Products = new List<Product>()
{
new Product()
{
ProductId = 1,
Name = "Book nr 1",
Price = 25
},
new Product()
{
ProductId = 2,
Name = "Book nr 2",
Price = 15
},
new Product()
{
ProductId = 3,
Name = "Book nr 3",
Price = 20
},
};
List<Order> Orders = new List<Order>()
{
new Order()
{
OrderId = 1,
ProductId = 1,
},
new Order()
{
OrderId = 2,
ProductId = 1,
},
new Order()
{
OrderId = 3,
ProductId = 2,
},
new Order()
{
OrderId = 4,
ProductId = NULL,
},
};
INRE KOPPLING
Frågesyntax
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId
select new
{
o.OrderId,
p.ProductId,
p.Name
}).ToList();
Metodsyntax
var joined = Products.Join(Orders, p => p.ProductId,
o => o.OrderId,
=> new
{
OrderId = o.OrderId,
ProductId = p.ProductId,
Name = p.Name
})
.ToList();
Resultat:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" }
Vänster yttre medlem
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId into g
from lj in g.DefaultIfEmpty()
select new
{
//For the empty records in lj, OrderId would be NULL
OrderId = (int?)lj.OrderId,
p.ProductId,
p.Name
}).ToList();
Resultat:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" }
KRÄSS GÅ MED
var joined = (from p in Products
from o in Orders
select new
{
o.OrderId,
p.ProductId,
p.Name
}).ToList();
Resultat:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" },
{ 4, NULL, NULL }
GRUPPGÅRD
var joined = (from p in Products
join o in Orders on p.ProductId equals o.ProductId
into t
select new
{
p.ProductId,
p.Name,
Orders = t
}).ToList();
Orders
innehåller nu ett IEnumerable<Order>
med alla länkade order.
Resultat:
{ 1, "Book nr 1", Orders = { 1, 2 } },
{ 2, "Book nr 2", Orders = { 3 } },
{ 3, "Book nr 3", Orders = { } },
Hur man går med på flera villkor
När du går med på ett enda villkor kan du använda:
join o in Orders
on p.ProductId equals o.ProductId
När du går med på flera använder du:
join o in Orders
on new { p.ProductId, p.CategoryId } equals new { o.ProductId, o.CategoryId }
Se till att båda anonyma objekt har samma egenskaper, och i VB.NET måste de vara markerade Key
, även om VB.NET tillåter flera Equals
klausuler separerade med And
:
Join o In Orders
On p.ProductId Equals o.ProductId And p.CategoryId Equals o.CategoryId
Frågesyntax och metatsyntax
Frågesyntax och metatsyntax är semantiskt identiska, men många tycker att syntax för frågan är enklare och lättare att läsa. Låt oss säga att vi måste hämta alla jämna objekt som beställts i stigande ordning från en samling nummer.
C #:
int[] numbers = { 0, 1, 2, 3, 4, 5, 6 };
// Query syntax:
IEnumerable<int> numQuery1 =
from num in numbers
where num % 2 == 0
orderby num
select num;
// Method syntax:
IEnumerable<int> numQuery2 = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
VB.NET:
Dim numbers() As Integer = { 0, 1, 2, 3, 4, 5, 6 }
' Query syntax: '
Dim numQuery1 = From num In numbers
Where num Mod 2 = 0
Select num
Order By num
' Method syntax: '
Dim numQuery2 = numbers.where(Function(num) num Mod 2 = 0).OrderBy(Function(num) num)
Kom ihåg att vissa frågor måste uttryckas som metodsamtal. Du måste till exempel använda ett metodsamtal för att uttrycka en fråga som hämtar antalet element som matchar ett angivet tillstånd. Du måste också använda ett metodsamtal för en fråga som hämtar det element som har det maximala värdet i en källsekvens. Så det kan vara en fördel med att använda metatsyntax för att göra koden mer konsekvent. Men du kan naturligtvis alltid använda metoden efter ett syntaxsamtal:
C #:
int maxNum =
(from num in numbers
where num % 2 == 0
select num).Max();
VB.NET:
Dim maxNum =
(From num In numbers
Where num Mod 2 = 0
Select num).Max();
LINQ-metoder och IEantal vs IQueryable
LINQ-förlängningsmetoder på IEnumerable<T>
tar faktiska metoder 1 , oavsett om anonyma metoder:
//C#
Func<int,bool> fn = x => x > 3;
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(fn);
'VB.NET
Dim fn = Function(x As Integer) x > 3
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(fn);
eller namngivna metoder (metoder som uttryckligen definieras som en del av en klass):
//C#
class Program {
bool LessThan4(int x) {
return x < 4;
}
void Main() {
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(LessThan4);
}
}
'VB.NET
Class Program
Function LessThan4(x As Integer) As Boolean
Return x < 4
End Function
Sub Main
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(AddressOf LessThan4)
End Sub
End Class
I teorin är det möjligt att analysera metodens IL , ta reda på vad metoden försöker göra och tillämpa metodens logik på alla underliggande datakällor, inte bara föremål i minnet. Men att analysera IL är inte för svag hjärta.
Lyckligtvis tillhandahåller .NET IQueryable<T>
-gränssnittet och förlängningsmetoderna på System.Linq.Queryable
för detta scenario. Dessa förlängningsmetoder tar ett uttrycksträd - en datastruktur som representerar kod - istället för en faktisk metod, som LINQ-leverantören sedan kan analysera 2 och konvertera till ett mer lämpligt formulär för att fråga den underliggande datakällan. Till exempel:
//C#
IQueryable<Person> qry = PersonsSet();
// Since we're using a variable of type Expression<Func<Person,bool>>, the compiler
// generates an expression tree representing this code
Expression<Func<Person,bool>> expr = x => x.LastName.StartsWith("A");
// The same thing happens when we write the lambda expression directly in the call to
// Queryable.Where
qry = qry.Where(expr);
'VB.NET
Dim qry As IQueryable(Of Person) = PersonSet()
' Since we're using a variable of type Expression(Of Func(Of Person,Boolean)), the compiler
' generates an expression tree representing this code
Dim expr As Expression(Of Func(Of Person, Boolean)) = Function(x) x.LastName.StartsWith("A")
' The same thing happens when we write the lambda expression directly in the call to
' Queryable.Where
qry = qry.Where(expr)
Om (till exempel) denna fråga är mot en SQL-databas, kan leverantören konvertera detta uttryck till följande SQL-sats:
SELECT *
FROM Persons
WHERE LastName LIKE N'A%'
och kör det mot datakällan.
Å andra sidan, om frågan strider mot ett REST-API, kan leverantören konvertera samma uttryck till ett API-samtal:
http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname
Det finns två primära fördelar med att skräddarsy en dataförfrågan baserad på ett uttryck (i motsats till att ladda hela samlingen i minnet och fråga lokalt):
- Den underliggande datakällan kan ofta fråga mer effektivt. Till exempel kan det mycket väl finnas ett index på
LastName
. Att ladda objekt i lokalt minne och fråga i minnet förlorar den effektiviteten. - Uppgifterna kan formas och minskas innan de överförs. I det här fallet behöver databasen / webbtjänsten bara returnera matchningsdata, i motsats till hela uppsättningen personer tillgängliga från datakällan.
anteckningar
1. Tekniskt tar de inte metoder, utan delegerar till exempel instanser som pekar på metoder . Men denna distinktion är irrelevant här.
2. Detta är orsaken till fel som " LINQ to Entities känner inte igen metoden 'System.String ToString ()' och denna metod kan inte översättas till ett butiksuttryck. ". LINQ-leverantören (i detta fall leverantören av Entity Framework) vet inte hur man ska analysera och översätta ett samtal till ToString
till motsvarande SQL.