MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Elementele de bază ale LINQ

LINQ (Language-Integrated Query) reprezintă un limbaj simplu și convenabil de interogare a surselor de date. Ca sursă de date poate fi un obiect care implementează interfața IEnumerable (de exemplu, colecții standard, array-uri), un set de date DataSet, un document XML. Dar, indiferent de tipul sursei, LINQ permite aplicarea aceleiași abordări pentru selecția datelor.

Există mai multe tipuri de LINQ:

  • LINQ to Objects: utilizat pentru lucrul cu array-uri și colecții
  • LINQ to Entities: folosit pentru accesarea bazelor de date prin tehnologia Entity Framework
  • LINQ to XML: aplicat la lucrul cu fișiere XML
  • LINQ to DataSet: utilizat pentru lucrul cu obiectul DataSet
  • Parallel LINQ (PLINQ): folosit pentru executarea interogărilor paralele

În acest capitol vom discuta în primul rând despre LINQ to Objects, dar în materialele următoare vor fi abordate și alte tipuri de LINQ. Majoritatea funcționalităților LINQ sunt concentrate în spațiul de nume System.LINQ. În proiectele .NET 6, acest spațiu de nume este conectat implicit.

Care este avantajul LINQ? Să vedem un exemplu simplu. Vom selecta dintr-un array șiruri care încep cu o anumită literă, de exemplu litera "T", și vom sorta lista rezultată:

string[] people = { "Tom", "Bob", "Sam", "Tim", "Tomas", "Bill" };

// creăm o listă nouă pentru rezultate
var selectedPeople = new List<string>();
// parcurgem array-ul
foreach (string person in people)
{
   // dacă șirul începe cu litera T, îl adăugăm în listă
   if (person.ToUpper().StartsWith("T"))
       selectedPeople.Add(person);
}
// sortăm lista
selectedPeople.Sort();

foreach (string person in selectedPeople)
   Console.WriteLine(person);

string[] people = { "Tom", "Bob", "Sam", "Tim", "Tomas", "Bill" }; // creăm o listă nouă pentru rezultate var selectedPeople = new List<string>(); // parcurgem array-ul foreach (string person in people) { // dacă șirul începe cu litera T, îl adăugăm în listă if (person.ToUpper().StartsWith("T")) selectedPeople.Add(person); } // sortăm lista selectedPeople.Sort(); foreach (string person in selectedPeople) Console.WriteLine(person);

Tim
Tom
Tomas

Deși această abordare funcționează, LINQ permite reducerea semnificativă a codului folosind o sintaxă intuitivă și concisă.

Pentru lucrul cu colecțiile putem utiliza două metode:

  • Operatori de interogare LINQ
  • Metode de extensie LINQ

Vom analiza ambele metode.

Operatori de interogare LINQ

Operatorii de interogare LINQ seamănă oarecum cu sintaxa interogărilor SQL, așa că, dacă ați lucrat vreodată cu interogări SQL, va fi mai ușor să înțelegeți conceptul general. Să modificăm exemplul anterior folosind operatorii de interogare LINQ:

string[] people = { "Tom", "Bob", "Sam", "Tim", "Tomas", "Bill" };

// creăm o nouă listă pentru rezultate
var selectedPeople = from p in people // transmitem fiecare element din people în variabila p
                   where p.ToUpper().StartsWith("T") // filtrare după criteriu
                   orderby p  // sortăm în ordine crescătoare
                   select p; // selectăm obiectul în colecția creată

foreach (string person in selectedPeople)
   Console.WriteLine(person);

În primul rând, codul a devenit mai scurt și mai simplu, iar rezultatul va fi același. În principiu, întreaga expresie ar putea fi scrisă pe o singură linie:

var selectedPeople = from p in people where p.ToUpper().StartsWith("T") orderby p select p;

Dar, pentru o mai bună claritate logică, am plasat fiecare subexpresie pe o linie separată.

Definiția simplă a unei interogări LINQ arată astfel:

from variabila in colectie
select variabila;

Ce face această interogare LINQ? Expresia from p in people parcurge toate elementele array-ului people și definește fiecare element ca p. Folosind variabila p, putem efectua diferite operațiuni asupra ei.

Deși nu specificăm tipul variabilei p, expresiile LINQ sunt puternic tipizate. Adică mediul de dezvoltare recunoaște automat că setul people constă din obiecte de tip string, astfel încât variabila p va fi tratată ca un șir de caractere.

Apoi, cu ajutorul operatorului where, se efectuează filtrarea obiectelor, iar dacă obiectul corespunde criteriului (în acest caz, litera inițială trebuie să fie "T"), acest obiect este transmis mai departe.

Operatorul orderby sortează în ordine crescătoare obiectele selectate.

Operatorul select transmite valorile selectate în selecția rezultată, care este returnată de expresia LINQ.

În acest caz, rezultatul expresiei LINQ este un obiect IEnumerable<T>. Adesea, selecția rezultată este definită folosind cuvântul cheie var, astfel încât compilatorul deduce automat tipul la timpul de compilare.

Metode de extensie LINQ

În afară de sintaxa standard from .. in .. select pentru crearea unei interogări LINQ, putem folosi metode de extensie speciale, care sunt definite pentru interfața IEnumerable. De obicei, aceste metode implementează aceeași funcționalitate ca operatorii LINQ de tip where sau orderby.

De exemplu:

string[] people = { "Tom", "Bob", "Sam", "Tim", "Tomas", "Bill" };

var selectedPeople = people.Where(p => p.ToUpper().StartsWith("T")).OrderBy(p => p);

foreach (string person in selectedPeople)
   Console.WriteLine(person);

Interogarea people.Where(p => p.ToUpper().StartsWith("T")).OrderBy(p => p) este echivalentă cu cea precedentă. Ea constă dintr-un lanț de metode Where și OrderBy. Aceste metode acceptă ca argument un delegat sau o expresie lambda.

Deși unele acțiuni le putem implementa atât cu operatori de interogare LINQ, cât și cu metode de extensie LINQ, nu fiecare metodă de extensie are un echivalent între operatorii LINQ. În acest caz, putem combina ambele abordări. De exemplu, folosim sintaxa standard LINQ și metoda de extensie Count(), care returnează numărul de elemente din selecție:

int number = (from p in people where p.ToUpper().StartsWith("T") select p).Count();
Console.WriteLine(number); // 3

Lista metodelor de extensie LINQ utilizate

  • Select: definește proiecția valorilor selectate
  • Where: definește filtrul selecției
  • OrderBy: sortează elementele în ordine crescătoare
  • OrderByDescending: sortează elementele în ordine descrescătoare
  • ThenBy: stabilește criterii suplimentare pentru sortarea elementelor în ordine crescătoare
  • ThenByDescending: stabilește criterii suplimentare pentru sortarea elementelor în ordine descrescătoare
  • Join: combină două colecții după un anumit criteriu
  • Aggregate: aplică o funcție agregată asupra elementelor secvenței, reducându-le la un singur obiect
  • GroupBy: grupează elementele după cheie
  • ToLookup: grupează elementele după cheie, adăugând toate elementele într-un dicționar
  • GroupJoin: realizează simultan combinarea colecțiilor și gruparea elementelor după cheie
  • Reverse: dispune elementele în ordine inversă
  • All: determină dacă toate elementele colecției îndeplinesc o anumită condiție
  • Any: determină dacă cel puțin un element din colecție îndeplinește o anumită condiție
  • Contains: determină dacă colecția conține un anumit element
  • Distinct: elimină elementele duplicate din colecție
  • Except: returnează diferența a două colecții, adică elementele care există doar într-o colecție
  • Union: combină două colecții omogene
  • Intersect: returnează intersecția a două colecții, adică elementele care apar în ambele colecții
  • Count: numără elementele colecției care îndeplinesc o anumită condiție
  • Sum: calculează suma valorilor numerice din colecție
  • Average: calculează valoarea medie a valorilor numerice din colecție
  • Min: găsește valoarea minimă
  • Max: găsește valoarea maximă
  • Take: selectează un număr specificat de elemente
  • Skip: omite un număr specificat de elemente
  • TakeWhile: returnează o secvență de elemente cât timp condiția este adevărată
  • SkipWhile: omite elementele din secvență cât timp acestea îndeplinesc o condiție specificată și apoi returnează elementele rămase
  • Concat: combină două colecții
  • Zip: combină două colecții conform unei anumite condiții
  • First: selectează primul element din colecție
  • FirstOrDefault: selectează primul element din colecție sau returnează valoarea implicită
  • Single: selectează singurul element din colecție; dacă colecția conține mai mult sau mai puțin de un element, se generează o excepție
  • SingleOrDefault: selectează singurul element din colecție; dacă colecția este goală, returnează valoarea implicită; dacă în colecție sunt mai multe elemente, se generează o excepție
  • ElementAt: selectează un element din secvență după un anumit index
  • ElementAtOrDefault: selectează un element din colecție după un anumit index sau returnează valoarea implicită dacă indexul este în afara intervalului permis
  • Last: selectează ultimul element din colecție
  • LastOrDefault: selectează ultimul element din colecție sau returnează valoarea implicită
← Lecția anterioară Lecția următoare →