Kihagyás

LINQ: Language Integrated Query

Adottak a következő osztályok, és listák ilyen objektumokból.

class Product
{
    public int ID;
    public string Name;
    public int Price;
    public int VATID;
}

class VAT
{
    public int ID;
    public int Percentage;
}

List<Product> products = ...
List<VAT> vat = ...

System.Linq

A Linq használatához a System.Linq névteret kell használnunk:

using System.Linq;

LINQ műveletek

Az alábbi példáknál, ahol elérhető, mindkét szintaktikát mutatjuk. A két féle szintaktika teljesen egyenértékű.

Szűrés

products.Where(p => p.Price < 1000)

from p in products
where p.Price < 1000

Projekció

products.Select(p => p.Name)

from p in products
select p.Name

Join

from p in products
join v in vat on p.VATID equals v.Id
select p.Price * v.Percentage

products.Join(vat, p => p.VATID, v => v.Id, (p, v) => p.Price * v.Percentage)

Sorrendezés

products.OrderBy[Descending](p => p.Name)
.ThenBy[Descending](p => p.Price)

from p in products
orderby p.Name, p.Price [descending]

Halmaz műveletek

products.Select(p => p.Name).Distinct()

products.Where(p => p.Price < 1000)
.Union( products.Where(p => p.Price > 100000) )

// hasonlóan Except, Intersect

Aggregáció

products.Count()

products.Select(p => p.Price).Average()

// hasonlóan Sum, Min, Max

Első, utolsó

products.First()

products.Last()

products.Where(p => p.Id==12).FirstOrDefault()

products.Where(p => p.Id==12).SingleOrDefault()

Lapozás

products.Take(10)

products.Skip(10).Take(10)

Tartalmazás (létezik-e)

products.Any(p => p.Price == 1234)

products.Where(p => p.Price == 1234).Any()

Csoportosítás

from p in products
group p by p.VATID

products.GroupBy(p => p.VATID)

Bonyolultabb projekció

A projekció során több féle módon kérhetjük az eredményeket.

Egész objektum

from p in products
...
select p

Ilyenkor az eredmény IQueryable<Product>, azaz Product osztály példányokat kapunk.

Csak bizonyos mező

from p in products
...
select p.Name

Ilyenkor az eredmény IQueryable<string>, azaz csak a neveket kapjuk.

Nevesített típusok

from p in products
...
select new MyType(p.Name, p.Price)

Ilyenkor az eredmény IQueryable<MyType>, ahol a MyType osztályt deklarálnunk kell, és a select-ben a konstruktorát hívjuk meg.

Névtelen típusok

from p in products
where p.Price > 1000
select new { ID = p.ID, Name = p.Name };

Névtelen típust a new { } szintaktikával hozhatunk létre. Ebből a fordító egy osztály definíciót készít a megadott nevű property-kkel. Ezt tipikusan akkor érdemes használni, ha egy-két tulajdonságot szeretnénk csak lekérdezni, és nincs szükségünk az egész objektumra.

Egy másik gyakori használati esete a névtelen típusnak, amikor nem egy rekord pár tulajdonságára vagyunk kíváncsiak, hanem számított értéket kérdezünk le, pl. a termékek neve és bruttó ára:

from p in products
join v in vat on p.VATID equals v.Id
select new { Name = p.Name, FullPrice = p.Price * (1 + v.Percentage / 100) }

LINQ kifejezések és az IEnumerable/IQueryable

Annak függvényében, hogy a Linq műveleteket milyen adatforráson használjuk, a products.Where(p => p.Price < 1000) jellegű kifejezések eredménye IEnumerable<T> vagy IQueryable<T>. Mindkettőre igaz, hogy az eredményhalmaz helyett csak leírók, azaz a művelet még nem került végrehajtásra. Ezt késői kiértékelésnek (deferred execution) hívjuk, ugyanis a leírt művelet csak akkor fog végrehajtódni, amikor az eredményekre ténylegesen is szükség van:

  • amikor elkezdünk iterálni az eredményhalmazon (pl. foreach),
  • amikor elkérjük az első elemet (lásd később, pl. .First()),
  • amikor listát kérünk az eredményhalmazból (.ToList()).

Ez a működés azért praktikus, mert így tudjuk szintaktikailag egymás után fűzni a LINQ műveleteket, mint például:

var l = products.Where(p => p.Price < 1000)
                .Where(p => p.Name.Contains('s'))
                .OrderBy(p => p.Name)
                .Select(p => p.Name)
...

// az l változó nem tartalmazza az eredményhalmazt

foreach(var x in l) // itt fog lefutni a tényleges kiértékelés
   { ... }

Kiértékelés

Ha mindenképpen szeretnénk kérni a lefuttatást, akkor tipikusan a .ToList()-et használjuk. Ezzel azonban vigyázzunk, fontoljuk meg, tényleg erre van-e szükségünk.

További információk és példák

Lambda kifejezések: https://www.tutorialsteacher.com/linq/linq-lambda-expression

Linq: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/


2021-11-03 Szerzők