Jazyk integrovaný dotaz - Language Integrated Query
Navrhl | společnost Microsoft |
---|---|
Vývojář | společnost Microsoft |
Psací disciplína | Silně napsané |
webová stránka | dokumenty |
Hlavní, důležitý implementace | |
Jazyky .NET (C#, F#, VB.NET ) | |
Ovlivněno | |
SQL, Haskell |
Jazyk integrovaný dotaz (LINQ, vyslovuje se „odkaz“) je a Microsoft .NET Framework komponenta, která přidává nativní data dotazování schopnosti Jazyky .NET, původně vydaná jako hlavní součást .NET Framework 3.5 v roce 2007.
LINQ rozšiřuje jazyk přidáním dotazu výrazy, které jsou podobné SQL příkazy a lze je použít k pohodlnému extrahování a zpracování dat z pole, vyčíslitelné třídy, XML dokumenty, relační databáze a zdroje dat třetích stran. Další použití, která využívají výrazy dotazu jako obecný rámec pro čitelné skládání libovolných výpočtů, zahrnují konstrukci obslužných rutin událostí[1] nebo monadický analyzátory.[2] Rovněž definuje sadu názvů metod (tzv standardní operátory dotazůnebo operátory standardní sekvence), spolu s pravidly překladu používanými překladačem k překladu syntaxe výrazů dotazu do výrazů pomocí plynulý styl (nazývá se syntaxe metody společností Microsoft) s těmito názvy metod, výrazy lambda a anonymní typy. Mnoho konceptů, které LINQ představilo, bylo původně testováno v Microsoftu Cω výzkumný projekt.
Porty LINQ existují pro PHP (PHPLinq ), JavaScript (linq.js ), Strojopis (linq.ts ), a ActionScript (ActionLinq ), ačkoli žádný není striktně ekvivalentní LINQ v .NET inspirovaných jazycích C #, F # a VB.NET (kde je součástí jazyka, nikoli externí knihovnou a kde často řeší širší škálu potřeb).[Citace je zapotřebí ]
Architektura LINQ v .NET Framework
Standard Query Operator API
V následujícím textu jsou popisy operátorů založeny na aplikaci práce s kolekcemi. Mnoho operátorů bere jako argumenty další funkce. Tyto funkce mohou být dodávány ve formě pojmenované metody nebo anonymní funkce.
Sada dotazu operátory definované LINQ je uživateli vystaveno jako operátor standardního dotazu (SQO) API. Operátory dotazů podporované API jsou:[3]
- Vybrat
Operátor Select provede a projekce na kolekci k výběru zajímavých aspektů prvků. Uživatel dodává libovolnou funkci ve formě pojmenovaného nebo výraz lambda, který promítá datové členy. Funkce je předána operátorovi jako a delegát.
- Kde
Operátor Where umožňuje definici sady pravidel predikátů, která se vyhodnocují pro každý objekt v kolekci, zatímco objekty, které neodpovídají pravidlu, jsou odfiltrovány. Predikát se operátorovi dodává jako delegát.
- Vyberte mnoho
U mapování poskytovaného uživatelem z prvků kolekce do kolekcí se provádějí sémanticky dva kroky. Nejprve je každý prvek namapován na odpovídající kolekci. Za druhé, výsledek prvního kroku se zploští o jednu úroveň. Poznámka: Select a Where are both implementable in terms of SelectMany, as long as singleton and empty collections are available. Díky výše uvedeným pravidlům překladu je pro poskytovatele LINQ povinné poskytovat další dva operátory.
- Součet / min. / Max. / Průměr
Tito operátoři volitelně berou funkci, která načte určitou číselnou hodnotu z každého prvku v kolekci a použije ji k vyhledání součtu, minima, maxima nebo průměru hodnot všech prvků v kolekci. Přetížené verze nemají žádnou funkci a chovají se, jako by byla dána identita jako lambda.
- Agregát
Zobecněný součet / min / max. Tento operátor přebírá funkci, která určuje, jak jsou dvě hodnoty kombinovány, aby vytvořily přechodný nebo konečný výsledek. Volitelně lze zadat počáteční hodnotu, což umožňuje libovolný výsledek typu agregace. Kromě toho lze dodat finalizační funkci, která vezme výsledek agregace na ještě jinou hodnotu.
- Připojte se / seskupte se
- Operátor join provede vnitřní spojení na dvou kolekcích na základě odpovídajících klíčů pro objekty v každé kolekci. Trvá dvě funkce jako delegáti, jednu pro každou kolekci, kterou provede na každém objektu v kolekci, aby extrahoval klíč z objektu. Také si vezme dalšího delegáta, ve kterém uživatel určí, které datové prvky, ze dvou shodných prvků, by se měly použít k vytvoření výsledného objektu. Operátor GroupJoin provádí a skupinové připojení. Stejně jako operátor Select jsou výsledky spojení instancemi jiné třídy se všemi datovými členy obou typů zdrojových objektů nebo jejich podmnožinou.
- Take / TakeWhile
- Operátor Take vybere prvních n objektů z kolekce, zatímco operátor TakeWhile, který vezme predikát, vybere ty objekty, které odpovídají predikátu (zastaví se u prvního objektu, který mu neodpovídá).
- Přeskočit / Přeskočit Zatímco
- Skip a SkipWhile operátory jsou doplňky Take a TakeWhile - přeskočí prvních n objektů z kolekce, nebo ty objekty, které odpovídají predikátu (pro případ SkipWhile).
- OfType
- Operátor OfType se používá k výběru prvků určitého typu.
- Concat
- Operátor Concat zřetězuje dvě sbírky.
- OrderBy / ThenBy
- Operátor OrderBy se používá k určení primárního řazení prvků v kolekci podle nějakého klíče. Výchozí řazení je ve vzestupném pořadí OrderByDescending operátor. ThenBy a ThenByDescending Určuje následné řazení prvků. Funkce pro extrahování hodnoty klíče z objektu je zadána uživatelem jako delegát.
- Zvrátit
- Obrátit operátor obrátí kolekci.
- Skupina vytvořená
- Operátor GroupBy převezme funkci, která extrahuje klíčovou hodnotu a vrátí kolekci
IGrouping
objekty, pro každou odlišnou hodnotu klíče. TheSeskupení
objekty lze poté použít k výčtu všech objektů pro konkrétní hodnotu klíče. - Odlišný
- Operátor Distinct odstraní duplikované instance objektu z kolekce. Přetížení operátoru přebírá objekt srovnávače rovnosti, který definuje kritéria odlišnosti.
- Unie / Křižovatka / Mimo
- Tito operátoři se používají k provádění a svaz, průsečík a rozdíl provoz na dvou sekvenciách. Každý z nich má přetížení, které přebírá objekt porovnávající rovnost, který definuje kritéria pro rovnost prvků.
- SequenceEqual
- Operátor SequenceEqual určuje, zda jsou všechny prvky ve dvou kolekcích stejné a ve stejném pořadí.
- First / FirstOrDefault / Last / LastOrDefault
- Tito operátoři berou predikát. První operátor vrátí první prvek, pro který predikát dává true, nebo pokud se nic neshoduje, vyvolá výjimku. Operátor FirstOrDefault je jako operátor First, kromě toho, že vrací výchozí hodnotu pro typ prvku (obvykle nulový odkaz) v případě, že nic neodpovídá predikátu. Poslední operátor načte poslední prvek, který odpovídá predikátu, nebo vyvolá výjimku v případě, že se nic neshoduje. LastOrDefault vrátí výchozí hodnotu prvku, pokud se nic neshoduje.
- Singl
- Single operátor vezme predikát a vrátí prvek, který odpovídá predikátu. Je vyvolána výjimka, pokud předikátu neodpovídá žádný nebo více než jeden prvek.
- SingleOrDefault
- SingleOrDefault operátor vezme predikát a vrátí prvek, který odpovídá predikátu. Pokud předikátu odpovídá více než jeden prvek, je vyvolána výjimka. Pokud žádný prvek neodpovídá predikátu, je vrácena výchozí hodnota.
- ElementAt
- Operátor ElementAt načte prvek v daném indexu v kolekci.
- Jakékoli / Všechny
- Operátor Any zkontroluje, zda v kolekci existují nějaké prvky odpovídající predikátu. Nevyberá prvek, ale vrátí hodnotu true, pokud je shodný alespoň jeden prvek. Vyvolání libovolného bez predikátu vrátí true, pokud kolekce není prázdná. Operátor All vrátí hodnotu true, pokud všechny prvky odpovídají predikátu.
- Obsahuje
- Operátor Contains zkontroluje, zda kolekce obsahuje daný prvek.
- Počet
- Operátor Count počítá počet prvků v dané kolekci. Přetížení brát predikát, počítá počet prvků odpovídajících predikátu.
Rozhraní Standard Query Operator API také určuje určité operátory, které převádějí kolekci na jiný typ:[3]
- AsEnumerable: Staticky zadá kolekci jako
IEnumerable
.[4] - AsQueryable: Staticky zadá kolekci jako
IQueryable
. - ToArray: Vytvoří pole
T []
ze sbírky. - ToList: Vytvoří a
Seznam
ze sbírky. - ToDictionary: Vytvoří a
Slovník
ze sbírky indexované klíčem K. Uživatelem poskytnutá projekční funkce extrahuje klíč z každého prvku. - ToLookup: Vytvoří a
Vyhledávání
ze sbírky indexované klíčem K. Uživatelem poskytnutá projekční funkce extrahuje klíč z každého prvku. - Obsazení: převádí negenerické
IEnumerable
sbírka jednomu zIEnumerable
odlitím každého prvku do typuT
. Alternativně převádí generikumIEnumerable
na jiné generikumIEnumerable
odlitím každého prvku z typuT
psátR
. Vyvolá výjimku v jakémkoli prvku nelze vrhnout na uvedený typ. - OfType: převede negenerické
IEnumerable
sbírka jednomu zIEnumerable
. Alternativně převádí generikumIEnumerable
na jiné generikumIEnumerable
pokusem o seslání každého prvku z typuT
psátR
. V obou případech je zahrnuta pouze podmnožina prvků úspěšně přenesených do cílového typu. Nejsou vyvolány žádné výjimky.
Jazyková rozšíření
Zatímco LINQ je primárně implementován jako knihovna pro .NET Framework 3.5 také definuje volitelná jazyková rozšíření, díky nimž jsou dotazy prvotřídní jazyková konstrukce a poskytnout syntaktický cukr pro psaní dotazů. Tato jazyková rozšíření byla původně implementována v C# 3.0, VB 9.0, F#[5] a Oxygen, s jinými jazyky jako Nemerle po oznámení předběžné podpory. Mezi jazyková rozšíření patří:[6]
- Syntaxe dotazu: Jazyk si může zvolit syntaxi dotazu, kterou nativně rozpozná. Tato jazyková klíčová slova musí být kompilátorem přeložena na příslušná volání metody LINQ.
- Implicitně zadané proměnné: Toto vylepšení umožňuje deklarovat proměnné bez zadání jejich typů. Jazyky C # 3.0 a Oxygene je deklarují pomocí
var
klíčové slovo. Ve verzi VB9.0Ztlumit
klíčové slovo bez deklarace typu dosahuje stejného. Takové objekty jsou stále silně napsaný; pro tyto objekty kompilátor odvozuje typy proměnných pomocí odvození typu, což umožňuje specifikovat a definovat výsledky dotazů bez deklarování typu mezilehlých proměnných. - Anonymní typy: Anonymní typy umožňují, aby třídy, které obsahují pouze deklarace datových členů, byly odvozeny kompilátorem. To je užitečné pro operátory Select a Join, jejichž typy výsledků se mohou lišit od typů původních objektů. Kompilátor používá odvození typu k určení polí obsažených ve třídách a generuje přistupující osoby a mutátory pro tato pole.
- Inicializátor objektu: Inicializátory objektů umožňují, aby byl objekt vytvořen a inicializován v jednom oboru, jak je požadováno pro operátory výběru a připojení.
- Lambda výrazy: Lambda výrazy umožňují predikáty a další projekční funkce psát přímo se stručnou syntaxí a podporují úplné lexikální uzavření. Jsou zachyceny do parametrů jako delegáti nebo stromy výrazů v závislosti na poskytovateli dotazů.
Například v dotazu vyberte všechny objekty v kolekci pomocí Nějaká vlastnost
méně než 10,
var Výsledek = z C v SomeCollection kde C.Nějaká vlastnost < 10 vybrat Nový {C.Nějaká vlastnost, C.Ostatní vlastnictví};pro každého (var výsledek v Výsledek){ Řídicí panel.WriteLine(výsledek);}
typy proměnných výsledek, C a Výsledek všechny jsou odvozeny kompilátorem v souladu s podpisy nakonec použitých metod. Základ pro výběr metod tvoří výsledek dotazu bez výrazového překladu
var Výsledek = SomeCollection .Kde(C => C.Nějaká vlastnost < 10) .Vybrat(C => Nový {C.Nějaká vlastnost, C.Ostatní vlastnictví});Výsledek.Pro každého(X => {Řídicí panel.WriteLine(X.ToString());})
Poskytovatelé LINQ
Specifikace C # 3.0 definuje vzor výrazu dotazu spolu s pravidly překladu z výrazu LINQ na výraz v podmnožině C # 3.0 bez výrazů LINQ. Takto definovaný překlad je ve skutečnosti netypizovaný, což kromě výrazů lambda, které lze interpretovat buď jako delegáty nebo stromy výrazů, umožňuje velkou míru flexibility pro knihovny, které chtějí vystavit části svého rozhraní jako klauzule výrazů LINQ. Například, LINQ k objektům pracuje naIEnumerable
s as delegáty, zatímco LINQ to SQL využívá výrazové stromy.
Stromy výrazů jsou jádrem mechanismu rozšiřitelnosti LINQ, kterým lze LINQ přizpůsobit pro mnoho zdrojů dat. Stromy výrazů jsou předány poskytovatelům LINQ, což jsou implementace specifické pro zdroj dat, které přizpůsobují dotazy LINQ pro použití se zdrojem dat. Pokud se tak rozhodnou, poskytovatelé LINQ analyzují stromy výrazů obsažené v dotazu, aby vygenerovaly základní části potřebné pro provedení dotazu. To mohou být fragmenty SQL nebo jakákoli jiná zcela odlišná reprezentace kódu jako další manipulovatelná data. LINQ je dodáván s LINQ Providers pro kolekce objektů v paměti, Microsoft SQL Server databáze, ADO.NET datové sady a dokumenty XML. Tito různí poskytovatelé definují různé příchutě LINQ:
LINQ k objektům
Zprostředkovatel LINQ to Objects se používá pro kolekce v paměti pomocí stroje pro provádění lokálních dotazů LINQ. Kód generovaný tímto poskytovatelem odkazuje na implementaci standardních operátorů dotazu, jak jsou definovány na Sekvence
vzor a umožňuje IEnumerable
sbírky, které mají být vyhledávány místně. Aktuální implementace LINQ to Objects provádí kontroly implementace rozhraní, aby bylo možné provádět rychlé testy členství, počty a indexované vyhledávací operace, pokud jsou podporovány runtime typem IEnumerable.[7][8][9]
LINQ to XML (dříve nazývané XLINQ)
Zprostředkovatel LINQ na XML převede dokument XML na kolekci XElement
objekty, které jsou poté dotazovány proti použití lokálního spouštěcího stroje, který je poskytován jako součást implementace standardního operátoru dotazu.[10]
LINQ to SQL (dříve nazývané DLINQ)
Zprostředkovatel LINQ to SQL umožňuje použít LINQ k dotazování Microsoft SQL Server databáze, včetně SQL Server Compact databáze. Vzhledem k tomu, že data serveru SQL Server mohou být umístěna na vzdáleném serveru a protože SQL Server má svůj vlastní stroj dotazů, LINQ to SQL nepoužívá stroj dotazu LINQ. Místo toho převede dotaz LINQ na SQL dotaz, který je poté odeslán na server SQL ke zpracování.[11] Protože však SQL Server ukládá data jako relační data a LINQ pracuje s daty zapouzdřenými v objektech, obě reprezentace musí být zmapováno navzájem. Z tohoto důvodu LINQ to SQL také definuje rámec mapování. Mapování se provádí definováním tříd, které odpovídají tabulkám v databázi, a obsahuje všechny nebo podmnožinu sloupců v tabulce jako datové členy.[12] Korespondence spolu s dalšími relační model atributy jako primární klíče, jsou specifikovány pomocí LINQ to SQL atributy. Například,
[Tabulka (Název = „Zákazníci“)]]veřejnost třída Zákazník{ [Sloupec (IsPrimaryKey = true)] veřejnost int CustID; [Sloupec] veřejnost tětiva Jméno zákazníka;}
Tato definice třídy se mapuje na tabulku s názvem Zákazníci
a dva datové členy odpovídají dvěma sloupcům. Třídy musí být definovány před použitím LINQ to SQL. Visual Studio 2008 zahrnuje návrháře mapování, který lze použít k vytvoření mapování mezi datovými schématy v objektu a relační doménou. Může automaticky vytvořit odpovídající třídy z a databázové schéma, stejně jako umožnit ruční úpravy k vytvoření jiného pohledu pomocí pouze podmnožiny tabulek nebo sloupců v tabulce.[12]
Mapování provádí DataContext
který převezme připojovací řetězec k serveru a lze jej použít k vygenerování Tabulka
kde T je typ, na který bude mapována databázová tabulka. The Tabulka
zapouzdřuje data v tabulce a implementuje IQueryable
rozhraní, takže je vytvořen strom výrazů, který zpracovává poskytovatel LINQ to SQL. Převede dotaz na T-SQL a načte sadu výsledků z databázového serveru. Protože zpracování probíhá na databázovém serveru, nelze použít místní metody, které nejsou definovány jako součást výrazů lambda představujících predikáty. Může však použít uložené procedury na serveru. Jakékoli změny sady výsledků jsou sledovány a lze je odeslat zpět na databázový server.[12]
LINQ to DataSets
Vzhledem k tomu, že poskytovatel LINQ to SQL (výše) funguje pouze s Microsoft SQL Server databází, aby bylo možné podporovat jakoukoli obecnou databázi, zahrnuje LINQ také LINQ k datovým sadám. Ke zpracování komunikace s databází používá ADO.NET. Jakmile jsou data v datových sadách ADO.NET, spustí LINQ to DataSets dotazy proti těmto datovým sadám.[13]
Výkon
Neprofesionální uživatelé mohou bojovat s jemnostmi v LINQ k objektům funkce a syntaxe. Naivní implementační vzory LINQ mohou vést ke katastrofickému snížení výkonu.[14][15]
LINQ to XML a LINQ to SQL výkon ve srovnání s ADO.NET závisí na případu použití.[16][17]
PLINQ
Verze 4 rozhraní .NET zahrnuje PLINQ nebo Paralelní LINQ, a paralelní spouštěcí stroj pro dotazy LINQ. Definuje ParallelQuery
třída. Jakákoli implementace IEnumerable
Rozhraní může využít výhod modulu PLINQ voláním AsParallel
metoda rozšíření definovaná ParallelEnumerable třídou v oboru názvů System.Linq rozhraní .NET Framework.[18] Stroj PLINQ může souběžně spouštět části dotazu na více vláknech a poskytovat tak rychlejší výsledky.[19]
Viz také
- Objektově-relační mapování (ORM)
- Neshoda objektově-relační impedance
- Seznam s porozuměním
- Líné hodnocení
Reference
- ^ "Rx framework".
- ^ „Monadic Parser Combinators using C # 3“. Citováno 2009-11-21.
- ^ A b „Standardní operátoři dotazů“. Microsoft. Citováno 2007-11-30.
- ^ "Enumerable Class". msdn. Microsoft. Citováno 15. února 2014.
- ^ „Query Expressions (F #)“. Dokumenty Microsoftu. Citováno 2012-12-19.
- ^ "LINQ Framework". Citováno 2007-11-30.
- ^ „Enumerable.ElementAt“. Citováno 2014-05-07.
- ^ „Enumerable.Contains“. Citováno 2014-05-07.
- ^ "Enumerable.Count". Citováno 2014-05-07.
- ^ „.NET Language-Integrated Query for XML Data“. Citováno 2007-11-30.
- ^ „LINQ to SQL“. Archivovány od originál dne 25.01.2013. Citováno 2007-11-30.
- ^ A b C „LINQ to SQL: .NET Language-Integrated Query for Relational Data“. Citováno 2007-11-30.
- ^ „LINQ to DataSets“. Archivovány od originál dne 25.01.2013. Citováno 2007-11-30.
- ^ Vider, Guy (21.12.2007). „Test výkonu LINQ: Můj první projekt Visual Studio 2008“. Citováno 2009-02-08.
- ^ Parsons, Jared (2008). „Zvýšení výkonu dotazu LINQ“. Microsoft Developer Network. Citováno 2014-03-19.
I když je pravda, že LINQ je výkonný a velmi efektivní, velké sady dat mohou stále způsobovat neočekávané problémy s výkonem
- ^ Alva, Jaime (06.08.2010). „Potenciální problémy s výkonem při kompilaci překládaných dotazů LINQ“. Microsoft Developer Network. Citováno 2014-03-19.
Při volání dotazu vícekrát s Entity Framework se doporučuje použít kompilované dotazy LINQ. Kompilace výsledků dotazu má za následek výkon, který se zobrazí při prvním použití dotazu, ale následná volání se provádějí mnohem rychleji
- ^ Kshitij, Pandey (2008-05-25). "Porovnání výkonu LinQ na SQL, ADO, C #". Citováno 2009-02-08.
- ^ "ParallelEnumerable Class". Citováno 2014-05-07.
- ^ „Programování ve věku souběžnosti: souběžné programování s PFX“. Citováno 2007-10-16.