linq Tutorial
Iniziare con linq
Ricerca…
Osservazioni
LINQ è un insieme di funzionalità introdotte in .NET Framework versione 3.5 che colma il divario tra il mondo degli oggetti e il mondo dei dati.
Tradizionalmente, le query sui dati sono espresse come semplici stringhe senza controllo del tipo in fase di compilazione o supporto IntelliSense. Inoltre, è necessario apprendere un linguaggio di query diverso per ciascun tipo di origine dati: database SQL, documenti XML, vari servizi Web e così via. LINQ crea una query in un costrutto linguistico di prima classe in C # e Visual Basic. Si scrivono query contro raccolte di oggetti fortemente tipizzate utilizzando parole chiave della lingua e operatori familiari.
Impostare
LINQ richiede .NET 3.5 o versione successiva (oppure .NET 2.0 con LINQBridge ).
Aggiungi un riferimento a System.Core , se non è stato ancora aggiunto.
Nella parte superiore del file, importa lo spazio dei nomi:
- C #
using System;
using System.Linq;
- VB.NET
Imports System.Linq
I diversi join in LINQ
Nei seguenti esempi, utilizzeremo i seguenti esempi:
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,
},
};
INNER JOIN
Sintassi delle query
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();
Sintassi del metodo
var joined = Products.Join(Orders, p => p.ProductId,
o => o.OrderId,
=> new
{
OrderId = o.OrderId,
ProductId = p.ProductId,
Name = p.Name
})
.ToList();
Risultato:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" }
SINISTRA ESTERNO
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();
Risultato:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" }
CROSS JOIN
var joined = (from p in Products
from o in Orders
select new
{
o.OrderId,
p.ProductId,
p.Name
}).ToList();
Risultato:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" },
{ 4, NULL, NULL }
GROUP JOIN
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();
Gli Orders
Propertie ora contengono un oggetto IEnumerable<Order>
con tutti gli ordini collegati.
Risultato:
{ 1, "Book nr 1", Orders = { 1, 2 } },
{ 2, "Book nr 2", Orders = { 3 } },
{ 3, "Book nr 3", Orders = { } },
Come aderire a più condizioni
Quando ti unisci a una singola condizione, puoi usare:
join o in Orders
on p.ProductId equals o.ProductId
Quando ti unisci a più persone, usa:
join o in Orders
on new { p.ProductId, p.CategoryId } equals new { o.ProductId, o.CategoryId }
Assicurati che entrambi gli oggetti anonimi abbiano le stesse proprietà, e in VB.NET, devono essere contrassegnati con Key
, anche se VB.NET consente più clausole Equals
separate da And
:
Join o In Orders
On p.ProductId Equals o.ProductId And p.CategoryId Equals o.CategoryId
Sintassi delle query e sintassi del metodo
La sintassi delle query e la sintassi del metodo sono semanticamente identiche, ma molte persone trovano la sintassi delle query più semplice e più facile da leggere. Diciamo che dobbiamo recuperare tutti gli oggetti pari ordinati in ordine crescente da una serie di numeri.
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)
Ricorda che alcune query devono essere espresse come chiamate di metodo. Ad esempio, è necessario utilizzare una chiamata al metodo per esprimere una query che recupera il numero di elementi che corrispondono a una condizione specificata. È inoltre necessario utilizzare una chiamata al metodo per una query che recupera l'elemento che ha il valore massimo in una sequenza di origine. Quindi questo potrebbe essere un vantaggio dell'uso della sintassi del metodo per rendere il codice più coerente. Tuttavia, ovviamente è sempre possibile applicare il metodo dopo una chiamata di sintassi di query:
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();
Metodi LINQ e IEnumerable vs IQueryable
I metodi di estensione LINQ su IEnumerable<T>
prendono i metodi attuali 1 , sia che si tratti di metodi anonimi:
//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);
o metodi con nome (metodi definiti esplicitamente come parte di una classe):
//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
In teoria, è possibile analizzare l'IL del metodo , capire che cosa il metodo sta tentando di fare e applicare la logica di quel metodo a qualsiasi origine dati sottostante, non solo oggetti in memoria. Ma analizzare IL non è per i deboli di cuore.
Fortunatamente, .NET fornisce l' IQueryable<T>
e i metodi di estensione a System.Linq.Queryable
, per questo scenario. Questi metodi di estensione prendono un albero di espressioni - una struttura dati che rappresenta il codice - invece di un metodo effettivo, che il provider LINQ può quindi analizzare 2 e convertire in un modulo più appropriato per interrogare l'origine dati sottostante. Per esempio:
//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)
Se (ad esempio) questa query è su un database SQL, il provider potrebbe convertire questa espressione nella seguente istruzione SQL:
SELECT *
FROM Persons
WHERE LastName LIKE N'A%'
ed eseguirlo contro la fonte dei dati.
D'altra parte, se la query è contro un'API REST, il provider può convertire la stessa espressione in una chiamata API:
http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname
Ci sono due principali vantaggi nel personalizzare una richiesta di dati basata su un'espressione (anziché caricare l'intera raccolta in memoria e interrogare localmente):
- L'origine dati sottostante può spesso eseguire query in modo più efficiente. Ad esempio, potrebbe esserci un indice su
LastName
. Caricare gli oggetti nella memoria locale e interrogare in memoria perde quell'efficienza. - I dati possono essere modellati e ridotti prima di essere trasferiti. In questo caso, il database / servizio web deve solo restituire i dati corrispondenti, in contrapposizione all'intero insieme di Persone disponibili dall'origine dati.
Gli appunti
1. Tecnicamente, in realtà non prendono metodi, ma delegano le istanze che puntano a metodi . Tuttavia, questa distinzione è irrilevante qui.
2. Questo è il motivo per cui errori come " LINQ to Entities" non riconosce il metodo "System.String ToString ()" e questo metodo non può essere tradotto in un'espressione di archivio. ". Il provider LINQ (in questo caso il provider Entity Framework) non sa come analizzare e tradurre una chiamata a ToString
in SQL equivalente.