linq Zelfstudie
Aan de slag met linq
Zoeken…
Opmerkingen
LINQ is een set functies geïntroduceerd in .NET Framework versie 3.5 die de kloof overbrugt tussen de wereld van objecten en de wereld van gegevens.
Traditioneel worden query's op gegevens uitgedrukt als eenvoudige tekenreeksen zonder typecontrole tijdens het compileren of ondersteuning voor IntelliSense. Bovendien moet u voor elk type gegevensbron een andere querytaal leren: SQL-databases, XML-documenten, verschillende webservices, enzovoort. LINQ maakt van een query een eersteklas taalconstructie in C # en Visual Basic. U schrijft query's op sterk getypeerde verzamelingen objecten met behulp van taalzoekwoorden en vertrouwde operatoren.
Opstelling
LINQ vereist .NET 3.5 of hoger (of .NET 2.0 met LINQBridge ).
Voeg een referentie toe aan System.Core , als deze nog niet is toegevoegd.
Importeer boven aan het bestand de naamruimte:
- C #
using System;
using System.Linq;
- VB.NET
Imports System.Linq
De verschillende joins in LINQ
In de volgende voorbeelden gebruiken we de volgende voorbeelden:
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,
},
};
BINNENKANTE
Zoekopdrachtsyntaxis
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();
Methode Syntaxis
var joined = Products.Join(Orders, p => p.ProductId,
o => o.OrderId,
=> new
{
OrderId = o.OrderId,
ProductId = p.ProductId,
Name = p.Name
})
.ToList();
Resultaat:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" }
LINKER BUITENKANTEL
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();
Resultaat:
{ 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();
Resultaat:
{ 1, 1, "Book nr 1" },
{ 2, 1, "Book nr 1" },
{ 3, 2, "Book nr 2" },
{ NULL, 3, "Book nr 3" },
{ 4, NULL, NULL }
GROEP VERBINDEN
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();
De Propertie- Orders
nu een IEnumerable<Order>
met alle gekoppelde bestellingen.
Resultaat:
{ 1, "Book nr 1", Orders = { 1, 2 } },
{ 2, "Book nr 2", Orders = { 3 } },
{ 3, "Book nr 3", Orders = { } },
Hoe deel te nemen aan meerdere voorwaarden
Wanneer u aan één voorwaarde deelneemt, kunt u het volgende gebruiken:
join o in Orders
on p.ProductId equals o.ProductId
Gebruik bij het deelnemen aan meerdere:
join o in Orders
on new { p.ProductId, p.CategoryId } equals new { o.ProductId, o.CategoryId }
Zorg ervoor dat beide anonieme objecten dezelfde eigenschappen hebben en in VB.NET moeten ze als Key
worden gemarkeerd, hoewel VB.NET meerdere Equals
clausules toestaat, gescheiden door And
:
Join o In Orders
On p.ProductId Equals o.ProductId And p.CategoryId Equals o.CategoryId
Querysyntaxis en methodesyntaxis
Querysyntaxis en methodesyntaxis zijn semantisch identiek, maar veel mensen vinden querysyntaxis eenvoudiger en gemakkelijker te lezen. Laten we zeggen dat we alle even items die in oplopende volgorde zijn besteld moeten halen uit een verzameling getallen.
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)
Vergeet niet dat sommige vragen moeten worden uitgedrukt als methodeaanroepen. U moet bijvoorbeeld een methode-aanroep gebruiken om een query uit te drukken die het aantal elementen ophaalt dat overeenkomt met een opgegeven voorwaarde. U moet ook een methode-aanroep gebruiken voor een query die het element ophaalt met de maximale waarde in een bronreeks. Dus dat kan een voordeel zijn van het gebruik van methodesyntaxis om de code consistenter te maken. Natuurlijk kunt u de methode echter altijd toepassen na een syntaxis van de zoekopdracht:
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-methoden en ontelbaar versus IQueryable
LINQ-uitbreidingsmethoden op IEnumerable<T>
nemen feitelijke methoden 1 , ongeacht of deze anonieme methoden zijn:
//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);
of benoemde methoden (methoden die expliciet als onderdeel van een klasse zijn gedefinieerd):
//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 theorie is het mogelijk om de IL van de methode te ontleden , erachter te komen wat de methode probeert te doen en de logica van die methode toe te passen op elke onderliggende gegevensbron, niet alleen objecten in het geheugen. Maar het ontleden van IL is niet voor bangeriken.
Gelukkig biedt .NET de IQueryable<T>
-interface en de uitbreidingsmethoden op System.Linq.Queryable
voor dit scenario. Deze uitbreidingsmethoden hebben een expressieboom - een gegevensstructuur die code vertegenwoordigt - in plaats van een daadwerkelijke methode, die de LINQ-provider vervolgens kan ontleden 2 en converteren naar een geschiktere vorm voor het doorzoeken van de onderliggende gegevensbron. Bijvoorbeeld:
//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)
Als (bijvoorbeeld) deze query betrekking heeft op een SQL-database, kan de provider deze expressie converteren naar de volgende SQL-instructie:
SELECT *
FROM Persons
WHERE LastName LIKE N'A%'
en voer het uit tegen de gegevensbron.
Aan de andere kant, als de query tegen een REST API is, kan de provider dezelfde expressie converteren naar een API-aanroep:
http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname
Het aanpassen van een gegevensverzoek op basis van een expressie heeft twee primaire voordelen (in tegenstelling tot het laden van de hele verzameling in het geheugen en lokaal opvragen):
- De onderliggende gegevensbron kan vaak efficiënter zoeken. Er kan bijvoorbeeld een index op
LastName
. Als u de objecten in het lokale geheugen laadt en in het geheugen opvraagt, verliest u die efficiëntie. - De gegevens kunnen worden gevormd en verkleind voordat ze worden overgedragen. In dit geval hoeft de database / webservice alleen de overeenkomende gegevens te retourneren, in tegenstelling tot de volledige set personen die beschikbaar is in de gegevensbron.
Notes
1. Technisch gezien nemen ze niet echt methoden, maar delegeren ze eerder instanties die naar methoden wijzen . Dit onderscheid is hier echter niet relevant.
2. Dit is de reden voor fouten zoals " LINQ to Entities herkent de methode 'System.String ToString ()' niet en deze methode kan niet worden vertaald in een winkelexpressie. ". De LINQ-provider (in dit geval de Entity Framework-provider) weet niet hoe hij een aanroep naar ToString
moet parseren en vertalen naar equivalente SQL.