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 jeint[]):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
intdostring. Všimněte si nového typuhighScoresQuery.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
scorescelý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
Countmetody . 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í.