Grunderna i frågeuttryck
Den här artikeln beskriver grundläggande begrepp som rör frågeuttryck i C#.
Vad är en fråga och vad gör den?
En fråga är en uppsättning instruktioner som beskriver vilka data som ska hämtas från en viss datakälla (eller källor) och vilken form och organisation de returnerade data ska ha. En fråga skiljer sig från de resultat som den producerar.
Vanligtvis ordnas källdata logiskt som en sekvens med element av samma slag. En SQL-databastabell innehåller till exempel en sekvens med rader. I en XML-fil finns det en "sekvens" av XML-element (även om XML-element ordnas hierarkiskt i en trädstruktur). En minnesintern samling innehåller en sekvens med objekt.
Från ett programs synvinkel är den specifika typen och strukturen för de ursprungliga källdata inte viktig. Programmet ser alltid källdata som en IEnumerable<T> eller IQueryable<T> samling. I LINQ till XML visas till exempel källdata som en IEnumerable
XElement<>.
Med tanke på den här källsekvensen kan en fråga göra något av tre saker:
Hämta en delmängd av elementen för att skapa en ny sekvens utan att ändra de enskilda elementen. Frågan kan sedan sortera eller gruppera den returnerade sekvensen på olika sätt, som du ser i följande exempel (anta
scores
är enint[]
):IEnumerable<int> highScoresQuery = from score in scores where score > 80 orderby score descending select score;
Hämta en sekvens med element som i föregående exempel men transformera dem till en ny typ av objekt. En fråga kan till exempel bara hämta familjenamnen från vissa kundposter i en datakälla. Eller så kan den hämta den fullständiga posten och sedan använda den för att konstruera en annan minnesintern objekttyp eller till och med XML-data innan den slutliga resultatsekvensen genereras. I följande exempel visas en projektion från en
int
till enstring
. Observera den nya typen avhighScoresQuery
.IEnumerable<string> highScoresQuery2 = from score in scores where score > 80 orderby score descending select $"The score is {score}";
Hämta ett singleton-värde om källdata, till exempel:
Antalet element som matchar ett visst villkor.
Det element som har det största eller minsta värdet.
Det första elementet som matchar ett villkor eller summan av vissa värden i en angiven uppsättning element. Följande fråga returnerar till exempel antalet poäng större än 80 från heltalsmatrisen
scores
:var highScoreCount = ( from score in scores where score > 80 select score ).Count();
I föregående exempel bör du notera användningen av parenteser runt frågeuttrycket före anropet Enumerable.Count till metoden. Du kan också använda en ny variabel för att lagra det konkreta resultatet.
IEnumerable<int> highScoresQuery3 = from score in scores where score > 80 select score; var scoreCount = highScoresQuery3.Count();
I föregående exempel körs frågan i anropet till Count
, eftersom Count
måste iterera över resultaten för att fastställa antalet element som returneras av highScoresQuery
.
Vad är ett frågeuttryck?
Ett frågeuttryck är en fråga som uttrycks i frågesyntaxen. Ett frågeuttryck är en förstklassig språkkonstruktion. Det är precis som alla andra uttryck och kan användas i alla sammanhang där ett C#-uttryck är giltigt. Ett frågeuttryck består av en uppsättning satser skrivna i en deklarativ syntax som liknar SQL eller XQuery. Varje sats innehåller i sin tur ett eller flera C#-uttryck, och dessa uttryck kan i sig vara antingen ett frågeuttryck eller innehålla ett frågeuttryck.
Ett frågeuttryck måste börja med en from-sats och måste avslutas med en select - eller grupp-sats . Mellan den första from
satsen och den sista select
eller group
-satsen kan den innehålla en eller flera av dessa valfria satser: där, orderby, join, let och even another from clauses. Du kan också använda in i nyckelordet för att aktivera resultatet av en join
eller group
-sats för att fungera som källa för fler frågesatser i samma frågeuttryck.
Frågevariabel
I LINQ är en frågevariabel en variabel som lagrar en fråga i stället för resultatet av en fråga. Mer specifikt är en frågevariabel alltid en uppräkningsbar typ som skapar en sekvens med element när den itereras över i en foreach
-instruktion eller ett direktanrop till dess IEnumerator.MoveNext() -metod.
Kommentar
Exempel i den här artikeln använder följande datakälla och exempeldata.
record City(string Name, long Population);
record Country(string Name, double Area, long Population, List<City> Cities);
record Product(string Name, string Category);
static readonly City[] cities = [
new City("Tokyo", 37_833_000),
new City("Delhi", 30_290_000),
new City("Shanghai", 27_110_000),
new City("São Paulo", 22_043_000),
new City("Mumbai", 20_412_000),
new City("Beijing", 20_384_000),
new City("Cairo", 18_772_000),
new City("Dhaka", 17_598_000),
new City("Osaka", 19_281_000),
new City("New York-Newark", 18_604_000),
new City("Karachi", 16_094_000),
new City("Chongqing", 15_872_000),
new City("Istanbul", 15_029_000),
new City("Buenos Aires", 15_024_000),
new City("Kolkata", 14_850_000),
new City("Lagos", 14_368_000),
new City("Kinshasa", 14_342_000),
new City("Manila", 13_923_000),
new City("Rio de Janeiro", 13_374_000),
new City("Tianjin", 13_215_000)
];
static readonly Country[] countries = [
new Country ("Vatican City", 0.44, 526, [new City("Vatican City", 826)]),
new Country ("Monaco", 2.02, 38_000, [new City("Monte Carlo", 38_000)]),
new Country ("Nauru", 21, 10_900, [new City("Yaren", 1_100)]),
new Country ("Tuvalu", 26, 11_600, [new City("Funafuti", 6_200)]),
new Country ("San Marino", 61, 33_900, [new City("San Marino", 4_500)]),
new Country ("Liechtenstein", 160, 38_000, [new City("Vaduz", 5_200)]),
new Country ("Marshall Islands", 181, 58_000, [new City("Majuro", 28_000)]),
new Country ("Saint Kitts & Nevis", 261, 53_000, [new City("Basseterre", 13_000)])
];
I följande kodexempel visas ett enkelt frågeuttryck med en datakälla, en filtreringssats, en beställningssats och ingen transformering av källelementen. - select
satsen avslutar frågan.
// 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 (var testScore in scoreQuery)
{
Console.WriteLine(testScore);
}
// Output: 93 90 82 82
I föregående exempel scoreQuery
är en frågevariabel, som ibland bara kallas för en fråga. Frågevariabeln lagrar inga faktiska resultatdata, som skapas i loopen foreach
. Och när -instruktionen foreach
körs returneras inte frågeresultatet via frågevariabeln scoreQuery
. I stället returneras de via iterationsvariabeln testScore
. Variabeln scoreQuery
kan itereras i en andra foreach
loop. Den ger samma resultat så länge varken den eller datakällan har ändrats.
En frågevariabel kan lagra en fråga som uttrycks i frågesyntax eller metodsyntax, eller en kombination av de två. I följande exempel är både queryMajorCities
och queryMajorCities2
frågevariabler:
City[] cities = [
new City("Tokyo", 37_833_000),
new City("Delhi", 30_290_000),
new City("Shanghai", 27_110_000),
new City("São Paulo", 22_043_000)
];
//Query syntax
IEnumerable<City> queryMajorCities =
from city in cities
where city.Population > 100000
select city;
// Execute the query to produce the results
foreach (City city in queryMajorCities)
{
Console.WriteLine(city);
}
// Output:
// City { Population = 120000 }
// City { Population = 112000 }
// City { Population = 150340 }
// Method-based syntax
IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 100000);
Å andra sidan visar följande två exempel variabler som inte är frågevariabler trots att var och en initieras med en fråga. De är inte frågevariabler eftersom de lagrar resultat:
var highestScore = (
from score in scores
select score
).Max();
// or split the expression
IEnumerable<int> scoreQuery =
from score in scores
select score;
var highScore = scoreQuery.Max();
// the following returns the same result
highScore = scores.Max();
var 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;
var largeCitiesList2 = largeCitiesQuery.ToList();
Explicit och implicit typning av frågevariabler
Den här dokumentationen innehåller vanligtvis den explicita typen av frågevariabel för att visa typrelationen mellan frågevariabeln och select-satsen. Du kan dock också använda nyckelordet var för att instruera kompilatorn att härleda typen av en frågevariabel (eller någon annan lokal variabel) vid kompileringstiden. Frågeexemplet som visades tidigare i den här artikeln kan till exempel också uttryckas med implicit inmatning:
var queryCities =
from city in cities
where city.Population > 100000
select city;
I föregående exempel är användningen av var valfri. queryCities
är en IEnumerable<City>
implicit eller explicit typ.
Starta ett frågeuttryck
Ett frågeuttryck måste börja med en from
sats. Den anger en datakälla tillsammans med en intervallvariabel. Intervallvariabeln representerar varje efterföljande element i källsekvensen när källsekvensen bläddras igenom. Intervallvariabeln skrivs starkt baserat på typen av element i datakällan. I följande exempel, eftersom countries
är en matris med Country
objekt, skrivs även intervallvariabeln som Country
. Eftersom intervallvariabeln är starkt skriven kan du använda punktoperatorn för att komma åt alla tillgängliga medlemmar av typen.
IEnumerable<Country> countryAreaQuery =
from country in countries
where country.Area > 500000 //sq km
select country;
Intervallvariabeln finns i omfånget tills frågan avslutas antingen med ett semikolon eller med en fortsättningssats .
Ett frågeuttryck kan innehålla flera from
satser. Använd fler from
satser när varje element i källsekvensen i sig är en samling eller innehåller en samling. Anta till exempel att du har en samling Country
objekt som var och en innehåller en samling City
objekt med namnet Cities
. Om du vill köra frågor mot objekten City
i varje Country
använder du två from
satser som visas här:
IEnumerable<City> cityQuery =
from country in countries
from city in country.Cities
where city.Population > 10000
select city;
Mer information finns i från -satsen.
Avsluta ett frågeuttryck
Ett frågeuttryck måste sluta med antingen en group
sats eller en select
-sats.
gruppsats
group
Använd -satsen för att skapa en sekvens med grupper ordnade efter en nyckel som du anger. Nyckeln kan vara vilken datatyp som helst. Följande fråga skapar till exempel en sekvens med grupper som innehåller ett eller flera Country
objekt och vars nyckel är en char
typ där värdet är den första bokstaven i ländernas namn.
var queryCountryGroups =
from country in countries
group country by country.Name[0];
Mer information om gruppering finns i gruppsatsen.
select-sats
select
Använd -satsen för att skapa alla andra typer av sekvenser. En enkel select
sats genererar bara en sekvens av samma typ av objekt som objekten som finns i datakällan. I det här exemplet innehåller Country
datakällan objekt. - orderby
satsen sorterar bara elementen i en ny ordning och select
satsen genererar en sekvens av de omsorterade Country
objekten.
IEnumerable<Country> sortedQuery =
from country in countries
orderby country.Area
select country;
Satsen select
kan användas för att omvandla källdata till sekvenser av nya typer. Den här omvandlingen heter också en projektion. I följande exempel select
projicerar satsen en sekvens av anonyma typer som endast innehåller en delmängd av fälten i det ursprungliga elementet. De nya objekten initieras med hjälp av en objektinitierare.
var queryNameAndPop =
from country in countries
select new
{
Name = country.Name,
Pop = country.Population
};
Så i det här exemplet var
krävs eftersom frågan genererar en anonym typ.
Mer information om alla sätt som en select
sats kan användas för att transformera källdata finns i select-satsen.
Fortsättningar med in i
Du kan använda nyckelordet into
i en select
eller group
-sats för att skapa en tillfällig identifierare som lagrar en fråga. Använd - into
satsen när du måste utföra extra frågeåtgärder på en fråga efter en grupperings- eller urvalsåtgärd. I följande exempel countries
grupperas enligt populationen i intervall på 10 miljoner. När dessa grupper har skapats filtrerar fler satser bort vissa grupper och sorterar sedan grupperna i stigande ordning. För att utföra dessa extra åtgärder krävs fortsättningen som representeras av countryGroup
.
// 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);
}
}
Mer information finns i.
Filtrering, ordning och anslutning
Mellan startsatsen from
och slutet select
eller group
-satsen är alla andra satser (where
, , join
orderby
, from
, let
) valfria. Valfria satser kan användas noll gånger eller flera gånger i en frågetext.
where-sats
where
Använd -satsen för att filtrera bort element från källdata baserat på ett eller flera predikatuttryck. where
Satsen i följande exempel har ett predikat med två villkor.
IEnumerable<City> queryCityPop =
from city in cities
where city.Population is < 200000 and > 100000
select city;
Mer information finns i where-sats.
orderby-sats
orderby
Använd -satsen för att sortera resultatet i antingen stigande eller fallande ordning. Du kan också ange sekundära sorteringsordningar. I följande exempel utförs en primär sortering av objekten country
med hjälp Area
av egenskapen . Den utför sedan en sekundär sortering med hjälp Population
av egenskapen .
IEnumerable<Country> querySortedCountries =
from country in countries
orderby country.Area, country.Population descending
select country;
Nyckelordet ascending
är valfritt. Det är standardsorteringsordningen om ingen ordning har angetts. Mer information finns i orderby-satsen.
kopplingssats
join
Använd -satsen för att associera och/eller kombinera element från en datakälla med element från en annan datakälla baserat på en likhetsjämförelse mellan angivna nycklar i varje element. I LINQ utförs kopplingsåtgärder på sekvenser av objekt vars element är olika typer. När du har sammanfogat två sekvenser måste du använda en select
-instruktion för group
att ange vilket element som ska lagras i utdatasekvensen. Du kan också använda en anonym typ för att kombinera egenskaper från varje uppsättning associerade element till en ny typ för utdatasekvensen. I följande exempel associeras prod
objekt vars Category
egenskap matchar en av kategorierna i strängmatrisen categories
. Produkter vars Category
sträng inte matchar i categories
filtreras bort. Instruktionen select
projicerar en ny typ vars egenskaper hämtas från både cat
och prod
.
var categoryQuery =
from cat in categories
join prod in products on cat equals prod.Category
select new
{
Category = cat,
Name = prod.Name
};
Du kan också utföra en gruppkoppling genom att lagra resultatet av join
åtgärden i en tillfällig variabel med hjälp av nyckelordet i . Mer information finns i kopplingssatsen.
let-sats
let
Använd -satsen för att lagra resultatet av ett uttryck, till exempel ett metodanrop, i en ny intervallvariabel. I följande exempel lagrar intervallvariabeln firstName
det första elementet i matrisen med strängar som returneras av 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 (var s in queryFirstNames)
{
Console.Write(s + " ");
}
//Output: Svetlana Claire Sven Cesar
Mer information finns i let-satsen.
Underfrågor i ett frågeuttryck
En frågesats kan i sig innehålla ett frågeuttryck, som ibland kallas för en underfråga. Varje underfråga börjar med en egen from
sats som inte nödvändigtvis pekar på samma datakälla i den första from
satsen. Följande fråga visar till exempel ett frågeuttryck som används i select-instruktionen för att hämta resultatet av en grupperingsåtgärd.
var queryGroupMax =
from student in students
group student by student.Year into studentGroup
select new
{
Level = studentGroup.Key,
HighestScore = (
from student2 in studentGroup
select student2.ExamScores.Average()
).Max()
};
Mer information finns i Utföra en underfråga för en grupperingsåtgärd.
Se även
Feedback
https://aka.ms/ContentUserFeedback.
Kommer snart: Under hela 2024 kommer vi att fasa ut GitHub-problem som feedbackmekanism för innehåll och ersätta det med ett nytt feedbacksystem. Mer information finns i:Skicka och visa feedback för