Sdílet prostřednictvím


Přehled standardních operátorů dotazů

Standardní operátory dotazu jsou klíčová slova a metody, které tvoří vzor LINQ. Jazyk C# definuje klíčová slova dotazu LINQ, která používáte pro nejběžnější výraz dotazu. Kompilátor překládá výrazy pomocí těchto klíčových slov na ekvivalentní volání metody. Dvě formy jsou synonymem. Jiné metody, které jsou součástí oboru názvů System.Linq, nemají ekvivalentní klíčová slova dotazu. V těchto případech je nutné použít syntaxi metody. Tato část popisuje všechna klíčová slova operátoru dotazu. Modul runtime a další balíčky NuGet přidávají další metody navržené pro práci s dotazy LINQ v jednotlivých verzích. Nejběžnější metody, včetně těch, které mají ekvivalenty klíčových slov dotazu, jsou popsané v této části. Úplný seznam metod dotazů podporovaných modulem runtime .NET najdete v dokumentaci k rozhraní System.Linq.Enumerable API. Kromě zde popsaných metod obsahuje tato třída metody pro zřetězení zdrojů dat, výpočet jedné hodnoty ze zdroje dat, jako je součet, průměr nebo jiná hodnota.

Důležité

Tyto ukázky používají zdroj dat System.Collections.Generic.IEnumerable<T>. Zdroje dat, které jsou založené na System.Linq.IQueryProvider, používají zdroje dat System.Linq.IQueryable<T> a stromy výrazů . Stromy výrazů mají omezení povolené syntaxe jazyka C#. Každý zdroj dat IQueryProvider, například EF Core, může navíc uplatňovat další omezení. Projděte si dokumentaci ke zdroji dat.

Většina z těchto metod působí na sekvencích, kde sekvence je objekt, jehož typ implementuje IEnumerable<T> rozhraní nebo rozhraní IQueryable<T>. Standardní operátory dotazů poskytují možnosti dotazu, včetně filtrování, projekce, agregace, řazení a dalších možností. Metody, které tvoří každou sadu, jsou členy rozšíření definované v jednotlivých EnumerableQueryable třídách. Jsou definovány jako členové rozšíření, kde je typ příjemce buď IEnumerable<T> nebo IQueryable<T> podle toho, na jakém typu pracují.

Rozdíl mezi sekvencemi IEnumerable<T> a IQueryable<T> určuje způsob spuštění dotazu za běhu.

Pro IEnumerable<T>vrácený výčtitelný objekt zachycuje argumenty, které byly předány metodě. Při výčtu tohoto objektu se použije logika operátoru dotazu a vrátí se výsledky dotazu.

Pro IQueryable<T>se dotaz přeloží do stromu výrazů . Strom výrazů lze přeložit na nativní dotaz, když zdroj dat dokáže dotaz optimalizovat. Knihovny, jako je Entity Framework, překládají dotazy LINQ do nativních dotazů SQL, které se spouštějí v databázi.

Následující příklad kódu ukazuje, jak můžete pomocí standardních operátorů dotazu získat informace o sekvenci.

string sentence = "the quick brown fox jumps over the lazy dog";
// Split the string into individual words to create a collection.
string[] words = sentence.Split(' ');

// Using query expression syntax.
var query = from word in words
            group word.ToUpper() by word.Length into gr
            orderby gr.Key
            select new { Length = gr.Key, Words = gr };

// Using method-based query syntax.
var query2 = words.
    GroupBy(w => w.Length, w => w.ToUpper()).
    Select(g => new { Length = g.Key, Words = g }).
    OrderBy(o => o.Length);

foreach (var obj in query)
{
    Console.WriteLine($"Words of length {obj.Length}:");
    foreach (string word in obj.Words)
        Console.WriteLine(word);
}

// This code example produces the following output:
//
// Words of length 3:
// THE
// FOX
// THE
// DOG
// Words of length 4:
// OVER
// LAZY
// Words of length 5:
// QUICK
// BROWN
// JUMPS

Pokud je to možné, dotazy v této části používají jako vstupní zdroj posloupnost slov nebo čísel. Pro dotazy, ve kterých se používají složitější vztahy mezi objekty, se používají následující zdroje, které modelují školu:

public enum GradeLevel
{
    FirstYear = 1,
    SecondYear,
    ThirdYear,
    FourthYear
};

public class Student
{
    public required string FirstName { get; init; }
    public required string LastName { get; init; }
    public required int ID { get; init; }

    public required GradeLevel Year { get; init; }
    public required List<int> Scores { get; init; }

    public required int DepartmentID { get; init; }
}

public class Teacher
{
    public required string First { get; init; }
    public required string Last { get; init; }
    public required int ID { get; init; }
    public required string City { get; init; }
}

public class Department
{
    public required string Name { get; init; }
    public int ID { get; init; }

    public required int TeacherID { get; init; }
}

Každý Student má stupeň, primární oddělení a řadu skóre. Teacher má také vlastnost City, která identifikuje areál, ve kterém učitel předměty pořádá. A Department má jméno a referenci na Teacher sloužícího jako vedoucí oddělení.

Sadu dat najdete ve zdrojovém úložišti .

Typy operátorů dotazů

Standardní operátory dotazů se liší v načasování jejich provádění v závislosti na tom, jestli vrací jednu hodnotu nebo posloupnost hodnot. Tyto metody, které vrátí jednu hodnotu (například Average a Sum), se spustí okamžitě. Metody, které vracejí sekvenci odloží provádění dotazu a vrátí výčtový objekt. Výstupní sekvenci jednoho dotazu můžete použít jako vstupní sekvenci do jiného dotazu. Dotazovací metody zřetězujete do jednoho dotazu, což umožňuje, aby dotazy dosáhly libovolné složitosti.

Operátory dotazů

V dotazu LINQ je prvním krokem zadání zdroje dat. V dotazu LINQ přichází klauzule from jako první, aby se zavedl zdroj dat (students) a proměnná rozsahu (student).

//queryAllStudents is an IEnumerable<Student>
var queryAllStudents = from student in students
                        select student;

Proměnná rozsahu se podobá proměnné iterace ve smyčce foreach s tím rozdílem, že ve výrazu dotazu nedojde k žádné skutečné iteraci. Při spuštění dotazu slouží proměnná rozsahu jako odkaz na každý následný prvek v students. Protože kompilátor může odvodit typ student, nemusíte ho explicitně zadávat. Do klauzule let můžete zavést více proměnných rozsahu. Další informace najdete v tématu let klauzule.

Poznámka:

Pro jiné než obecné zdroje dat, jako například ArrayList, musíte explicitně určit typ proměnné rozsahu. Další informace najdete v tématu Jak dotazovat ArrayList pomocí LINQ (C#) a z klauzule.

Jakmile získáte zdroj dat, můžete na daném zdroji dat provést libovolný počet operací:

Tabulka syntaxe výrazů dotazu

Následující tabulka uvádí standardní operátory dotazu, které mají ekvivalentní klauzule výrazu dotazu.

Metoda Syntaxe výrazu dotazu jazyka C#
Cast Použijte explicitně typovanou proměnnou rozsahu:

from int i in numbers

(Více informací najdete v části z oddílu.)
GroupBy group … by …

nebo

group … by … into …

(Další informace najdete v tématu klauzule skupiny.)
GroupJoin<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,IEnumerable<TInner>, TResult>) join … in … on … equals … into …

(Více informací naleznete v , klauzuli join.)
Join<TOuter,TInner,TKey,TResult>(IEnumerable<TOuter>, IEnumerable<TInner>, Func<TOuter,TKey>, Func<TInner,TKey>, Func<TOuter,TInner,TResult>) join … in … on … equals …

(Více informací naleznete v , klauzuli join.)
OrderBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) orderby

(Další informace viz ORDER BY klauzule.)
OrderByDescending<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) orderby … descending

(Další informace viz ORDER BY klauzule.)
Select select

(Více informací viz klauzule 'select' .)
SelectMany Více from klauzulí.

(Více informací najdete v části z oddílu.)
ThenBy<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) orderby …, …

(Další informace viz ORDER BY klauzule.)
ThenByDescending<TSource,TKey>(IOrderedEnumerable<TSource>, Func<TSource,TKey>) orderby …, … descending

(Další informace viz ORDER BY klauzule.)
Where where

(Další informace najdete v klauzuli , kde téma.)

Transformace dat pomocí LINQ

Language-Integrated Dotaz (LINQ) není pouze o načítání dat. Je to také výkonný nástroj pro transformaci dat. Pomocí dotazu LINQ můžete jako vstup použít zdrojovou sekvenci a upravit ji mnoha způsoby, abyste vytvořili novou výstupní sekvenci. Samotnou sekvenci můžete upravit beze změny samotných prvků řazením a seskupením. Ale možná nejvýkonnější funkcí dotazů LINQ je schopnost vytvářet nové typy. Klauzule select vytvoří výstupní prvek ze vstupního elementu. Použijete ho k transformaci vstupního elementu na výstupní element:

  • Sloučí více vstupních sekvencí do jedné výstupní sekvence, která má nový typ.
  • Vytvořte výstupní sekvence, jejichž prvky se skládají pouze z jedné nebo několika vlastností každého prvku ve zdrojové sekvenci.
  • Vytvořte výstupní sekvence, jejichž prvky se skládají z výsledků operací prováděných se zdrojovými daty.
  • Vytváření výstupních sekvencí v jiném formátu Můžete například transformovat data z řádků SQL nebo textových souborů do XML.

Tyto transformace můžete kombinovat různými způsoby ve stejném dotazu. Kromě toho můžete jako vstupní sekvenci nového dotazu použít výstupní sekvenci jednoho dotazu. Následující příklad transformuje objekty v datové struktuře v paměti na elementy XML.


// Create the query.
var studentsToXML = new XElement("Root",
    from student in students
    let scores = string.Join(",", student.Scores)
    select new XElement("student",
                new XElement("First", student.FirstName),
                new XElement("Last", student.LastName),
                new XElement("Scores", scores)
            ) // end "student"
        ); // end "Root"

// Execute the query.
Console.WriteLine(studentsToXML);

Kód vytvoří následující výstup XML:

<Root>
  <student>
    <First>Svetlana</First>
    <Last>Omelchenko</Last>
    <Scores>97,90,73,54</Scores>
  </student>
  <student>
    <First>Claire</First>
    <Last>O'Donnell</Last>
    <Scores>56,78,95,95</Scores>
  </student>
  ...
  <student>
    <First>Max</First>
    <Last>Lindgren</Last>
    <Scores>86,88,96,63</Scores>
  </student>
  <student>
    <First>Arina</First>
    <Last>Ivanova</Last>
    <Scores>93,63,70,80</Scores>
  </student>
</Root>

Další informace najdete v tématu Vytváření stromů XML v jazyce C# (LINQ to XML).

Výsledky jednoho dotazu můžete použít jako zdroj dat pro další dotaz. Tento příklad ukazuje, jak uspořádat výsledky operace spojení. Tento dotaz vytvoří skupinové spojení a pak seřadí skupiny podle department prvku, který je stále v rámci rozsahu. Uvnitř inicializátoru anonymního typu poddotaz seřadí veškeré odpovídající prvky ze sekvence students.

var orderedQuery = from department in departments
                   join student in students on department.ID equals student.DepartmentID into studentGroup
                   orderby department.Name
                   select new
                   {
                       DepartmentName = department.Name,
                       Students = from student in studentGroup
                                  orderby student.LastName
                                    select student
                   };

foreach (var departmentList in orderedQuery)
{
    Console.WriteLine(departmentList.DepartmentName);
    foreach (var student in departmentList.Students)
    {
        Console.WriteLine($"  {student.LastName,-10} {student.FirstName,-10}");
    }
}
/* Output:
Chemistry
  Balzan     Josephine
  Fakhouri   Fadi
  Popov      Innocenty
  Seleznyova Sofiya
  Vella      Carmen
Economics
  Adams      Terry
  Adaobi     Izuchukwu
  Berggren   Jeanette
  Garcia     Cesar
  Ifeoma     Nwanneka
  Jamuike    Ifeanacho
  Larsson    Naima
  Svensson   Noel
  Ugomma     Ifunanya
Engineering
  Axelsson   Erik
  Berg       Veronika
  Engström   Nancy
  Hicks      Cassie
  Keever     Bruce
  Micallef   Nicholas
  Mortensen  Sven
  Nilsson    Erna
  Tucker     Michael
  Yermolayeva Anna
English
  Andersson  Sarah
  Feng       Hanying
  Ivanova    Arina
  Jakobsson  Jesper
  Jensen     Christiane
  Johansson  Mark
  Kolpakova  Nadezhda
  Omelchenko Svetlana
  Urquhart   Donald
Mathematics
  Frost      Gaby
  Garcia     Hugo
  Hedlund    Anna
  Kovaleva   Katerina
  Lindgren   Max
  Maslova    Evgeniya
  Olsson     Ruth
  Sammut     Maria
  Sazonova   Anastasiya
Physics
  Åkesson    Sami
  Edwards    Amy E.
  Falzon     John
  Garcia     Debra
  Hansson    Sanna
  Mattsson   Martina
  Richardson Don
  Zabokritski Eugene
*/

Ekvivalentní dotaz pomocí syntaxe metody se zobrazí v následujícím kódu:

var orderedQuery = departments
    .GroupJoin(students, department => department.ID, student => student.DepartmentID,
    (department, studentGroup) => new
    {
        DepartmentName = department.Name,
        Students = studentGroup.OrderBy(student => student.LastName)
    })
    .OrderBy(department => department.DepartmentName);


foreach (var departmentList in orderedQuery)
{
    Console.WriteLine(departmentList.DepartmentName);
    foreach (var student in departmentList.Students)
    {
        Console.WriteLine($"  {student.LastName,-10} {student.FirstName,-10}");
    }
}

I když můžete použít orderby klauzuli s jednou nebo více zdrojovými sekvencemi před spojením, obecně ji nedoporučujeme. Někteří zprostředkovatelé LINQ nemusí zachovat toto řazení po spojení. Další informace viz příkaz join.

Viz také