Základy výrazů dotazů

Tento článek představuje základní koncepty související s výrazy dotazů v jazyce C#.

Co je dotaz a co dělá?

Dotaz je sada instrukcí, která popisuje, jaká data se mají načíst z daného zdroje dat (nebo zdrojů) a jaký tvar a organizaci by měla vrácená data mít. Dotaz se liší od výsledků, které vytváří.

Obecně platí, že zdrojová data jsou logicky uspořádaná jako posloupnost prvků stejného druhu. Například tabulka SQL obsahuje sekvenci řádků. V souboru XML existuje "posloupnost" elementů XML (i když jsou uspořádány hierarchicky ve stromové struktuře). Kolekce v paměti obsahuje sekvenci objektů.

Z pohledu aplikace není konkrétní typ a struktura původních zdrojových dat důležitý. Aplikace vždy vidí zdrojová data jako kolekci IEnumerable<T> IQueryable<T> nebo . Například v LINQ to XML se zdrojová data zviditelní jako IEnumerable <XElement>.

Vzhledem k této zdrojové sekvenci může dotaz provést jednu ze tří věcí:

  • Načtěte podmnožinu prvků, aby se vytvářely nové sekvence beze změny jednotlivých prvků. Dotaz pak může vrácenou sekvenci seřadit nebo seskupit různými způsoby, jak je znázorněno v následujícím příkladu (předpokládejme, scores že je int[] ):

    IEnumerable<int> highScoresQuery =
        from score in scores
        where score > 80
        orderby score descending
        select score;
    
  • Načte posloupnost prvků jako v předchozím příkladu, ale transformuje je na nový typ objektu. Dotaz může například načíst pouze příjmení z určitých záznamů zákazníků ve zdroji dat. Nebo může načíst úplný záznam a pak ho použít k vytvoření jiného typu objektu v paměti nebo dokonce dat XML před generováním konečné sekvence výsledků. Následující příklad ukazuje projekci z int do string . Všimněte si nového typu highScoresQuery .

    IEnumerable<string> highScoresQuery2 =
        from score in scores
        where score > 80
        orderby score descending
        select $"The score is {score}";
    
  • Načtěte jednu hlavní hodnotu zdrojových dat, například:

    • Počet prvků, které odpovídají určité podmíně.

    • Prvek, který má největší nebo nejmenší hodnotu.

    • První prvek, který odpovídá podmětu, nebo součet konkrétních hodnot v zadané sadě prvků. Například následující dotaz vrátí počet skóre větších než 80 z pole scores celých čísel:

      int highScoreCount =
          (from score in scores
           where score > 80
           select score)
           .Count();
      

      V předchozím příkladu si všimněte použití závorek kolem výrazu dotazu před voláním Count metody . Můžete to také vyjádřit pomocí nové proměnné pro uložení konkrétního výsledku. Tato technika je čitelná, protože udržuje proměnnou, která ukládá dotaz odděleně od dotazu, který ukládá výsledek.

      IEnumerable<int> highScoresQuery3 =
          from score in scores
          where score > 80
          select score;
      
      int scoreCount = highScoresQuery3.Count();
      

V předchozím příkladu je dotaz proveden ve volání , protože musí iterovat výsledky, aby bylo možné určit počet prvků Count Count vrácených parametrem highScoresQuery .

Co je výraz dotazu?

Výraz dotazu je dotaz vyjádřený v syntaxi dotazu. Výraz dotazu je jazyková konstrukce první třídy. Je to stejně jako jakýkoli jiný výraz a lze ho použít v libovolném kontextu, ve kterém je výraz jazyka C# platný. Výraz dotazu se skládá ze sady klauzulí napsaných v deklarativní syntaxi podobné SQL nebo XQuery. Každá klauzule zase obsahuje jeden nebo více výrazů jazyka C# a tyto výrazy mohou být buď výrazy dotazu, nebo obsahují výraz dotazu.

Výraz dotazu musí začínat klauzulí from a musí končovat klauzulí select nebo group. Mezi první klauzulí a poslední klauzulí nebo může obsahovat jednu nebo více těchto volitelných klauzulí: where , orderby , join , let a ještě další from select z group klauzulí. Pomocí klíčového slova into můžete také povolit, aby výsledek klauzule or sloužil jako zdroj pro další klauzule dotazu join ve stejném group výrazu dotazu.

Proměnná dotazu

V jazyce LINQ je proměnná dotazu libovolná proměnná, která místo výsledků dotazu ukládá dotaz. Konkrétně jde o to, že proměnná dotazu je vždy vyčíslitelný typ, který vytvoří posloupnost prvků, pokud je iterována v příkazu nebo přímém volání foreach své IEnumerator.MoveNext metody.

Následující příklad kódu ukazuje jednoduchý výraz dotazu s jedním zdrojem dat, jednou klauzulí filtrování, jednou klauzulí řazení a žádnou transformací zdrojových elementů. Klauzule select ukončí dotaz.

static void Main()
{
    // Data source.
    int[] scores = { 90, 71, 82, 93, 75, 82 };

    // Query Expression.
    IEnumerable<int> scoreQuery = //query variable
        from score in scores //required
        where score > 80 // optional
        orderby score descending // optional
        select score; //must end with select or group

    // Execute the query to produce the results
    foreach (int testScore in scoreQuery)
    {
        Console.WriteLine(testScore);
    }
}
// Outputs: 93 90 82 82

V předchozím příkladu scoreQuery je proměnná dotazu, která se někdy označuje jako dotaz . Proměnná dotazu ukládá žádná skutečná výsledná data, která se produkuje ve foreach smyčce. A při spuštění příkazu se výsledky dotazu foreach nevrátily prostřednictvím proměnné dotazu scoreQuery . Místo toho se vrací prostřednictvím iterační proměnné testScore . Proměnnou scoreQuery lze iterovat ve druhé smyčce. foreach Výsledkem budou stejné výsledky, pokud nebyl změněn ani zdroj dat.

Proměnná dotazu může ukládat dotaz vyjádřený syntaxí dotazu nebo syntaxí metody nebo jejich kombinací. V následujících příkladech jsou proměnné dotazu queryMajorCities i queryMajorCities2 :

//Query syntax
IEnumerable<City> queryMajorCities =
    from city in cities
    where city.Population > 100000
    select city;

// Method-based syntax
IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 100000);

Na druhé straně následující dva příklady ukazují proměnné, které nejsou proměnnými dotazu, i když je každý z nich inicializován pomocí dotazu. Nejsou to proměnné dotazu, protože ukládají výsledky:

int highestScore =
    (from score in scores
     select score)
    .Max();

// or split the expression
IEnumerable<int> scoreQuery =
    from score in scores
    select score;

int highScore = scoreQuery.Max();
// the following returns the same result
int highScore = scores.Max();

List<City> largeCitiesList =
    (from country in countries
     from city in country.Cities
     where city.Population > 10000
     select city)
       .ToList();

// or split the expression
IEnumerable<City> largeCitiesQuery =
    from country in countries
    from city in country.Cities
    where city.Population > 10000
    select city;

List<City> largeCitiesList2 = largeCitiesQuery.ToList();

Další informace o různých způsobech vyjádření dotazů najdete v tématu Syntaxe dotazů a syntaxe metod v jazyce LINQ.

Explicitní a implicitní psaní proměnných dotazu

Tato dokumentace obvykle poskytuje explicitní typ proměnné dotazu, aby bylo možné zobrazit vztah typu mezi proměnnou dotazu a klauzulí select. Můžete však také použít klíčové slovo var, které kompilátoru instruuje, aby odvodil typ proměnné dotazu (nebo jakékoli jiné místní proměnné) v době kompilace. Příklad dotazu, který byl uveden dříve v tomto tématu, lze například vyjádřit také pomocí implicitního psaní:

// Use of var is optional here and in all queries.
// queryCities is an IEnumerable<City> just as
// when it is explicitly typed.
var queryCities =
    from city in cities
    where city.Population > 100000
    select city;

Další informace najdete v tématu Implicitně typované místní proměnné a Relace typů v operacích dotazů LINQ.

Spuštění výrazu dotazu

Výraz dotazu musí začínat from klauzulí . Určuje zdroj dat společně s proměnnou rozsahu. Proměnná rozsahu představuje každý po sobě jdoucí prvek ve zdrojové sekvenci při procházení zdrojové sekvence. Proměnná rozsahu je silného typu na základě typu prvků ve zdroji dat. V následujícím příkladu, protože je pole objektů, proměnná countries Country rozsahu je také typována jako Country . Vzhledem k tomu, že proměnná rozsahu je silného typu, můžete použít operátor tečky pro přístup ke všem dostupným členům typu.

IEnumerable<Country> countryAreaQuery =
    from country in countries
    where country.Area > 500000 //sq km
    select country;

Proměnná rozsahu je v oboru, dokud se dotaz neukončuje středníkem nebo klauzulí pokračování.

Výraz dotazu může obsahovat více from klauzulí. Další klauzule použijte, pokud je každý prvek ve zdrojové sekvenci sám from kolekcí nebo obsahuje kolekci. Předpokládejme například, že máte kolekci objektů, z nichž každý obsahuje kolekci objektů Country City s názvem Cities . Pokud chcete City dotazovat objekty v Country každé , použijte dvě from klauzule, jak je znázorněno zde:

IEnumerable<City> cityQuery =
    from country in countries
    from city in country.Cities
    where city.Population > 10000
    select city;

Další informace najdete v tématu o klauzuli from.

Ukončení výrazu dotazu

Výraz dotazu musí končít buď group klauzulí, nebo select klauzulí .

group – klauzule

Pomocí group klauzule můžete vytvořit posloupnost skupin uspořádaných podle klíče, který zadáte. Klíč může být libovolný datový typ. Například následující dotaz vytvoří posloupnost skupin, které obsahují jeden nebo více objektů a jejichž klíč je typem, jehož hodnotou je první písmeno Country char názvů zemí.

var queryCountryGroups =
    from country in countries
    group country by country.Name[0];

Další informace o seskupování najdete v tématu group – klauzule.

select – klauzule (C#)

K vytvoření select všech ostatních typů sekvencí použijte klauzuli . Jednoduchá klauzule pouze vytvoří sekvenci stejného typu objektů jako objekty, které jsou select obsaženy ve zdroji dat. V tomto příkladu zdroj dat obsahuje Country objekty. Klauzule pouze seřadí prvky do nového pořadí a klauzule vytvoří sekvenci orderby select přeuspořádaných Country objektů.

IEnumerable<Country> sortedQuery =
    from country in countries
    orderby country.Area
    select country;

Klauzuli select lze použít k transformaci zdrojových dat na sekvence nových typů. Tato transformace se také nazývá projekce. V následujícím příkladu select klauzule prodá sekvenci anonymních typů, která obsahuje pouze podmnožinu polí v původním prvku. Všimněte si, že nové objekty jsou inicializovány pomocí inicializátoru objektu.

// Here var is required because the query
// produces an anonymous type.
var queryNameAndPop =
    from country in countries
    select new { Name = country.Name, Pop = country.Population };

Další informace o všech způsobech použití klauzule k transformaci zdrojových select dat najdete v tématu select – klauzule.

Pokračování s into

Klíčové slovo v klauzuli or můžete použít into k select vytvoření group dočasného identifikátoru, který ukládá dotaz. To proveďte, když musíte provést další operace dotazu na dotaz po operaci seskupení nebo výběru. V následujícím příkladu countries jsou seskupeny podle populace v rozsahu 10 milionů. Po vytvoření těchto skupin další klauzule odfiltrují některé skupiny a pak je seřadí vzestupně. K provedení těchto dalších operací se vyžaduje pokračování countryGroup reprezentované pomocí .

// percentileQuery is an IEnumerable<IGrouping<int, Country>>
var percentileQuery =
    from country in countries
    let percentile = (int) country.Population / 10_000_000
    group country by percentile into countryGroup
    where countryGroup.Key >= 20
    orderby countryGroup.Key
    select countryGroup;

// grouping is an IGrouping<int, Country>
foreach (var grouping in percentileQuery)
{
    Console.WriteLine(grouping.Key);
    foreach (var country in grouping)
        Console.WriteLine(country.Name + ":" + country.Population);
}

Další informace najdete v tématu .

Filtrování, řazení a spojování

Mezi počáteční klauzulí a koncovou klauzulí nebo jsou všechny from select ostatní group klauzule ( , , where , , ) join orderby from let volitelné. Kterákoli z volitelných klauzulí může být v textu dotazu použita nulakrát nebo vícekrát.

where – klauzule

Klauzule where slouží k odfiltrování prvků ze zdrojových dat na základě jednoho nebo více predikátových výrazů. Klauzule where v následujícím příkladu má jeden predikát se dvěma podmínkami.

IEnumerable<City> queryCityPop =
    from city in cities
    where city.Population < 200000 && city.Population > 100000
    select city;

Další informace najdete v tématu where – klauzule.

orderby – klauzule

K orderby seřazení výsledků ve vzestupném nebo sestupném pořadí použijte klauzuli . Můžete také zadat sekundární pořadí řazení. Následující příklad provádí primární řazení objektů country pomocí Area vlastnosti . Potom provede sekundární řazení pomocí Population vlastnosti .

IEnumerable<Country> querySortedCountries =
    from country in countries
    orderby country.Area, country.Population descending
    select country;

Klíčové slovo je volitelné. Pokud není zadáno žádné pořadí, jedná se o výchozí ascending pořadí řazení. Další informace najdete v tématu klauzule orderby.

join – klauzule

Pomocí klauzule můžete přidružit nebo kombinovat prvky z jednoho zdroje dat s prvky z jiného zdroje dat na základě porovnání rovnosti mezi zadanými klíči v join každém prvku. V jazyce LINQ se operace spojení provádějí v sekvencích objektů, jejichž prvky jsou různé typy. Po dokončení dvou sekvencí musíte pomocí příkazu nebo určit, který prvek se má select group uložit do výstupní sekvence. Anonymní typ můžete použít také ke kombinování vlastností z každé sady přidružených prvků do nového typu pro výstupní sekvenci. Následující příklad přidruží prod objekty, Category jejichž vlastnost odpovídá jedné z kategorií v poli categories řetězců. Odfiltrují se produkty, jejichž řetězec neodpovídá Category categories žádnému řetězci v . Příkaz select pro projektování nového typu, jehož vlastnosti jsou převzaty z i cat prod .

var categoryQuery =
    from cat in categories
    join prod in products on cat equals prod.Category
    select new { Category = cat, Name = prod.Name };

Můžete také provést spojení skupiny uložením výsledků operace do dočasné join proměnné pomocí klíčového slova into. Další informace najdete v tématu join – klauzule.

let – klauzule

Klauzule slouží k uložení výsledku výrazu, jako je volání let metody, do nové proměnné rozsahu. V následujícím příkladu proměnná rozsahu ukládá první prvek pole firstName řetězců, který je vrácen pomocí Split .

string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" };
IEnumerable<string> queryFirstNames =
    from name in names
    let firstName = name.Split(' ')[0]
    select firstName;

foreach (string s in queryFirstNames)
    Console.Write(s + " ");
//Output: Svetlana Claire Sven Cesar

Další informace najdete v tématu let – klauzule.

Poddotazy ve výrazu dotazu

Klauzule dotazu může sama obsahovat výraz dotazu, který se někdy označuje jako poddotaz. Každý poddotaz začíná vlastní klauzulí, která nemusí nutně odkazovat na stejný zdroj dat from v první from klauzuli. Například následující dotaz ukazuje výraz dotazu, který se používá v příkazu select k načtení výsledků operace seskupení.

var queryGroupMax =
    from student in students
    group student by student.GradeLevel into studentGroup
    select new
    {
        Level = studentGroup.Key,
        HighestScore =
            (from student2 in studentGroup
             select student2.Scores.Average())
             .Max()
    };

Další informace najdete v tématu Provedení poddotazu u operace seskupení.

Viz také