Linq
Upcoming SlideShare
Loading in...5
×
 

Linq

on

  • 544 views

Linq presentation

Linq presentation

Statistics

Views

Total Views
544
Views on SlideShare
537
Embed Views
7

Actions

Likes
0
Downloads
1
Comments
0

2 Embeds 7

http://adamabonyi.azurewebsites.net 5
https://twitter.com 2

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Linq Linq Presentation Transcript

  • LINQ Adam Abonyi Jan Ambrož
  • Agenda    Co je to LINQ? Jak lze LINQ použít? Co musím znát, abychom se mohli dotazovat v LINQu? Pokračování    LINQ to Objects (anything and everything) LINQ to XML LINQ to ADO.NET (to SQL, to DataSets)
  • LINQ - Language INtegrated Query  Vlastní pro rodinu .NET jazyků  Visual Basic, C# a další  Dotazování jako součást programovacího jazyka  Dotazování nad „libovolným“ datovým zdrojem   SQL, XML, IEnumerable, další... Využití znalosti metadat  Typová kontrola, našeptávání (Intellisense), kontrola syntaxe
  • LINQ - co můžeme použít?  Základní operace   Třízení   GroupBy Agregační funkce   OrderBy, OrderByDescending Seskupování (Group)   Select, From, Where Count, Min, Max, Average, ... Spojování pomocí operátoru Join a další operace
  • LINQ - co musíme znát?  Lambda výrazy  Expression trees (Stromy výrazů)  Extension Metody  Lokální dedukce typů  Anonymní typy  Inicializace dat  Lambda Výrazy – Kód jako data
  • LINQ - lambda výrazy  Předání metody jako parametr jiné metodě   Doplnění nějakého obecného chování (např. jak se mají porovnávat dva řetězce) Zápis lambda výrazů v C# 3.0   Generické delegáty jsou součástí .NET knihoven Func<…>, liší se počtem typových parametrů Možnost zápisu anonymních delegátů (arg1, arg2) => výraz delegate TResult Func<TResult>(); delegate TResult Func<T1, TResult>(T1 a1); delegate TResult Func<T1, T2, TResult>(T1 a1, T2 a2); Func<string, string, string> add = (a, b) => a + " " + b; string res = add("Hello", "world"); Console.WriteLine(res);
  • LINQ - lambda výrazy • Dva typy podle výrazu za šipkou – Výraz – tedy to co lze napsat v přiřazení ( a = <výraz>; ) – Blok – umožňuje zapsat více-řádkový kód Func<int, int, int> add = (a, b) => a + b; Func<int, int, int> add = (a, b) => { Console.WriteLine("scitam!"); return a + b; }; • Typy parametrů C# pozná (většinou) automaticky – Ale lze je případně doplnit Func<int, int, int> add = (int a, int b) => a + b;
  • LINQ - expression trees  „kód jako data“   Lambda výrazy typu Expression<Func<…>> Neformálně: Vrátí objekty, které popisují to, co jsme do výrazu napsali - něco jako vrátit zdrojový kód výrazu Expression<Func<int, int, int>> exprAdd = (a, b) => a + b;  O tom později   .. je to pro LINQ klíčové! Stojí na tom implementace „LINQ to SQL“
  • LINQ – extension metody  Zápis static class StringUtils { static public string Reverse(this string s) { StringBuilder sb = new StringBuilder(); for (int i = s.Length - 1; i >= 0; i--) sb.Append(s[i]); return sb.ToString(); } }  Užití string s = "dlrow olleH"; string r = s.Reverse();
  • LINQ - extension metody  Jak to přesně funguje?      Musí být statická, ve statické třídě První parametr označen klíčovým slovem this Musí být v jmenném prostoru otevřeném pomocí using Existuje-li normální metoda se stejným jménem, volá se ta. Je to bezpečné?   Samozřejmě, extension metoda má práva přistupovat jen k public členům původní třídy Funguje to pouze jako „syntactic sugar“ Enumerable.Select( Enumerable.Where(t, n => n % 2 == 0), n => n * n); vs. t.Where(n => n % 2 == 0).Select(n => n * n);
  • LINQ - dedukce typu  Klíčové slůvko var pro deklaraci proměnné     Typ proměnné se odvodí z výrazu na pravé straně Je to typově bezpečné a typ je vždy známý Výraz na pravé straně nesmí být null Lze použít i ve for a foreach cyklech // C# 3.0 var i = 5; var s = "Hello"; var d = 1.0; var numbers = new int[] { 1, 2, 3 }; var orders = new Dictionary<int, Order>(); ' Visual Basic 9 Dim e = 10
  • LINQ - dedukce typu  Pro Visual Studio se jedná o obyčejné proměnné   … a zobrazuje jejich typ C# kompilátor zná typ
  • LINQ - dedukce typu • Vše je stále typově bezpečné – Nejedná se tedy o typ object! ' Visual Basic 9 Dim e = 10 Chyba: Neznámý typ! // C# var e var n var d 3.0 Chyba: n je typu ‘int’ Vhodné použití  = null; = 10; n.SomeFunction(); = new Dictionary<string, ICollection<string>>(); • Používejte ji rozumně! – Inicializace „ošklivých“ typů – Klíčové pro anonymní typy (uvidíme později)
  • LINQ - anonymní typy var person = new { Name = „Adam", City = "Praha"}; Console.WriteLine(person.City); Dim person = New With {.Name = „Adam", .City = "Praha"} person.City = "Brno" Console.WriteLine(person.City)   Vytváří typ, který má uvedené vlastnosti Jméno typu nelze zapsat…    Lze je používat pouze lokálně díky dedukcí typů Nelze vrátit z metody (pouze jako object) (pozn.: v C# mají pouze get, ve VB i set)
  • LINQ - inicializace dat  Inicializace objektů  Podobná syntaxe jako při zápisu anonymních typů // Anonymní typ var p = new { Name = „Adam", City = "Praha" }; // Pojmenovaný typ var p = new Person { Name = „Adam", City = "Praha" };  Lze použít na libovolné .NET typy s vlastnostmi var f = new Form { BackColor = Color.Green, Text = "Hello!" };  Je možné volat vlastní konstruktor při vytváření var c = new Customer("John", "Doe") { City = "New York" };
  • LINQ - inicializace objektů  Jak to funguje?  Úsporný zápis pro obyčejné nastavování vlastností class Customer { public string Name { get; set; } public string Country { get; set; } public string City { get; set; } } var c = new Customer { Name = "Jose", Country = "Spain", City="Barcelona" } Dim c = New Customer With { .Name = "Jose", .Country = "Spain", .City="Barcelona" } Customer _temp = new Customer(); _temp.Name = "Jose"; _temp.Country = "Spain"; _temp.City = "Barcelona"; Customer c = _temp;
  • LINQ - inicializace kolekcí  Podobné, jako inicializace pole, ale pro ostatní kolekce var numsA = new int[] { 1, 2, 3, 4, 5, 6 }; var numsL = new List<int> { 1, 2, 3, 4, 5, 6 };  Samozřejmě, možno kombinovat s inicializací objektů var custs = new List<Customer> { new Customer { Name = "John", Surname = "Doe", City = "New York" }, new Customer { Name = "Tomas", Surname="Petricek", City = "Prague" } };  Lze inicializovat i komplikovanější kolekce var spellings = new Dictionary<int, string> { { 0, "Zero" }, { 1, "One" }, { 2, "Two" }, { 3, "Three" } };
  • LINQ - kód jako data  Druhá možnost, jak deklarovat lambda výrazy   Místo Func<…> použijeme Expression<Func<…>> To je reprezentace zdrojového kódu výrazu using System.Linq.Expressions; // Visual Basic Dim square As Expression(Of Func(Of Integer, String)) = _ Function(i) "Number: " + (i.ToString()) // C# Expression<Func<int, string>> square = (i) => "Number: " + (i.ToString());  Použijeme-li WriteLine/ToString, získáme pseudokód: Console.WriteLine(square); // Vypíše: i => ("Number: " + i.ToString())
  • LINQ - kód jako data  Volba mezi stromem a delegátem na základě typu   Při deklaraci nelze používat var! Func<...> Kompiluje se jako delegát Expression<Func<...>> Uloží se jako data (strom) Kód funkce se uloží jako data (strom)     Kód (strom) se např. dá přeložit do jazyka SQL Stromy lze konstruovat z kódu Stromy lze upravovat (vytvořit změněnou kopii) Stromy lze kompilovat na spustitelný kód (za běhu)
  • LINQ - kód jako data  PŘÍKLAD: Strom následujícího výrazu: Expression<Func<int, string>> square = (i) => "Number: " + (i.ToString()); ParameterExpression (Type=int, Name =“i”) LambdaExpression (params => body) ConstantExpression (“Number: “) BinaryExpression (Type=“Add”) MethodCallExpression (Object.ToString)  ParameterExpression (Type=int, Name=“i”) Výraz (strom) bude k dispozici za běhu programu  Může být různě zpracován (např. přeložen do SQL)
  • LINQ - dotazy  Pomocí lambda výrazů a extension metod lze zapsat některé obvyklé operace s daty: var q = db.Products .Where(p => p.ProductName.StartsWith("C")) .Select(p => p.ProductName);  Ale je to dost dobré? … jak by vypadal Join nebo GroupBy? var q = from p in db.Products where p.ProductName.StartsWith("C“) select p.ProductName;   Pro tyto běžné příklady má C# (a VB) rozšíření, které přidává dotazy přímo do programovacího jazyka Vnitřně se stále vše překládá pomocí extension metod
  • LINQ - základní dotazy  Standardní dotazy s Where a Select:  ID kategorií, které se jmenují Beverages var q = from c in db.Categories where c.CategoryName == "Beverages" select c.CategoryID;  Chceme pouze první takovou… var q = (from c in db.Categories where c.CategoryName == "Beverages" select c.CategoryID).First();  Vracíme anonymní typ – pouze jméno a cenu produktu: var q = from p in db.Products where p.CategoryID == 1 select new { p.ProductName, Price = p.UnitPrice };
  • LINQ - dotazy  Řazení položek pomocí klauzule OrderBy  Řazení produktů podle jména: var q = from p in db.Products orderby p.ProductName select p;  Vzestupné (ascending) a sestupné (descending) pořadí: var q = from p in db.Products orderby p.ProductName ascending, p.UnitPrice descending select p;
  • LINQ - dotaz Začíná klíčovým slovem from Následují klauzule from, join, let, where, orderby from id in source { from id in source | join id in source on expr equals expr [ into id ] | let id = expr | Na konec select where condition | nebo group by orderby ordering, ordering, … } select expr | group expr by key [ into id query ] Může následovat klauzule into
  • LINQ - dotazy  Spojení více zdrojů dat pomocí operace Join  Použití více klauzulí from v dotazu: var q = from p in db.Products from c in db.Categories where p.CategoryID == c.CategoryID select new { Category = c.CategoryName, Product = p.ProductName };  Totéž pomocí operátoru Join (inner join) var q = from p in db.Products join c in db.Categories on p.CategoryID equals c.CategoryID select new { Category = c.CategoryName, Product = p.ProductName };  Pozn.: Outer join lze zapsat pomocí metody DefaultIfEmpty()
  • LINQ - dotazy  Seskupování pomocí group … by  Narozdíl od SQL vrací objekty skutečně po skupinách (nikoliv jako seznam, kde jsou skupiny po sobě) var q = from p in db.Products group p by p.CategoryID; foreach (var group in q) { Console.WriteLine(group.Key); foreach (var prod in group) Console.WriteLine(prod.ProductName); }  Použití klauzule into pro další práci se skupinami: var q = from p in db.Products group p by p.CategoryID into g select new { g.Key, Count = (from p in g where p.UnitPrice > 10.0M select g) .Count() };
  • LINQ - dotazy  Zápis dotazů pomocí volání metod  Počet produktů v dané kategorii: var q = db.Products .Where(p => p.CategoryID == 2) .Count();  Seřadíme podle jména a vrátíme index produktu a jméno: var q = db.Products .OrderBy(p => p.ProductName) .Select((p, index) => new { Index = index, Name = p.ProductName });  „Stránkování“ pomocí operátorů Skip a Take: var q = db.Products .OrderBy(p => p.ProductName) .Skip(5*page).Take(page);
  • Část druhá LINQ to * Jan Ambrož
  • LINQ obecně  Proč potřebujeme nové technologie pro práci s daty? C# 3.0 VB 9.0 Others… LINQ: Langauge INtegrated Query LINQ to Objects LINQ to DataSets LINQ to SQL LINQ to Entities LINQ to XML <book> <title/> <author/> <year/> <price/> </book> Objekty Databáze XML
  • LINQ – pod pokličkou  Většina použití LINQu se týká kolekcí dat    tedy rozhraní IEnumerable<T> pod .NET Základní implementace ve statické třídě Enumerable Pro použití nutné importovat namespace System.Linq     tím je umožněno využívat Extension Methods definované statickou třídou Enumerable tato třída definuje metody pro všechny potřebné operátory použití každého operátoru vrací mírně modifikované rozhraní IEnumerable<T> výsledkem je tedy opět rozhraní IEnumerable<T>, tedy opět kolekce dat
  • LINQ – pod pokličkou  Ne vždy je však toto řešení ideální   např. LINQ to SQL – nechceme nahrávat obsah celé tabulky a pak filtrovat a řadit data Řešením je použití rozhraní IQueryable<T>     tvorba Expression Tree používáním LINQ operátorů využití Extension Methods definovaných třídou Queryable tzv. Provider následně transformuje Expression Tree do výsledné podoby vlastního dotazu funkčnost není omezena, rozhraní je potomkem IEnumerable<T>, stále tedy lze využít např. foreach cyklus k procházení výsledků
  • LINQ – pod pokličkou  Použití IQueryable<T>    LINQ to SQL – nejprve je vytvořen dotaz, který je následně transformován do SQL jazyka LINQ to Anything – dotazy vůči webovým službám, webovým stránkám, ... Další možností je manuální implementace operátorů     definice vlastní třídy obsahující metody Where, Select, ... díky tomu, že kompilátor překládá jazykové konstrukce LINQu na volání metod, vše funguje automaticky výhodou je absolutní kontrola nad prováděním dotazu nevýhodou pak samozřejmě implementační náročnost
  • LINQ – pod pokličkou IEnumerable<T> (data) where IQueryable<T> (data) (objekty) where orderby (objekty) orderby (dotaz) select (výsledek) select (výsledek)
  • LINQ to Objects  Možnost použít LINQ na libovolné kolekce dat      v prostředí .NETu tedy každý objekt implementující IEnumerable<T> (všechny třídy jako List<T>, Queue<T>, Stack<T>, ale také (a hlavně) libovolné pole) ve většině případů je zápis pomocí LINQu úspornější a čitelnější některé operace, jako např. řazení dat nebo použití operátoru Join, jsou bez použití LINQ velmi krkolomné použití LINQu přibližuje klasické programování deklarativnímu mohou však nastat případy, kdy použití LINQ není optimální
  • LINQ to Objects – absurdní příklad  Následující příklad ukazuje, že téměř vše lze zapsat jako LINQ dotaz int i = 5; var q = from t in new int[] { i } where t == 6 select t; if (q.Any()) Console.WriteLine(“i je 6”);  Totéž lze samozřejmě jednoduše vyjádřit jako int i = 5; if (i == 6) Console.WriteLine(“i je 6”);
  • LINQ to Objects – příklady  Dotaz na znaky v řetězci string aString = "ABCDE99F-J74-12-89A"; // Select only those characters that are numbers IEnumerable<char> stringQuery = from ch in aString where Char.IsDigit(ch) select ch; // Execute the query foreach (char c in stringQuery) Console.Write(c + " "); // Call the Count method on the existing query. int count = stringQuery.Count(); Console.WriteLine("Count = {0}", count);
  • LINQ to Objects – příklady  LINQ v kombinaci s Regular Expressions // Create the regular expression to find all things "Visual". Regex searchTerm = new Regex(@"Visual(Basic|C#|C++|J#|SourceSafe|Studio)"); // Search the contents of each .htm file. Remove the where clause // to find even more matches! This query produces a list of files // where a match was found, and a list of the matches in that file. // Note: Explicit typing of "Match" in select clause. This is // required because MatchCollection is not a generic IEnumerable // collection. var queryMatchingFiles = from file in fileList where file.Extension == ".htm” let fileText = File.ReadAllText(file.FullName) let matches = searchTerm.Matches(fileText) where searchTerm.Matches(fileText).Count > 0 select new { name = file.FullName, matches = from Match match in matches select match.Value };
  • LINQ to Objects – příklady  Seskupení souborů podle velikosti // Get all file names at the selected path var fileNames = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); // Transform file names into objects describing the file var fileList = from name in fileNames select new FileInfo(name); // Group the files according to their size, leaving out // files that are less than 200000 bytes. var querySizeGroups = from file in fileList let len = file.Length where len > 0 group file by (len / 100000) into fileGroup where fileGroup.Key >= 2 orderby fileGroup.Key descending select fileGroup;
  • LINQ to Objects – příklady  Ukázka použití operátoru Join string[] names = File.ReadAllLines(@"../../../names.csv"); string[] scores = File.ReadAllLines(@"../../../scores.csv"); // Merge the data sources using a named type. // Note the dynamic creation of a list of ints for the // TestScores member. We skip 1 because the first string // in the array is the student ID, not an exam score. var queryNamesScores = from name in names let x = name.Split(',') from score in scores let s = score.Split(',') where x[2] == s[0] select new Student() { FirstName = x[0], LastName = x[1], ID = Convert.ToInt32(x[2]), ExamScores = (from scoreAsText in s.Skip(1) select Convert.ToInt32(scoreAsText.ToList()) };
  • LINQ to XML  Změna přístupu ke XML dokumentům v .NETu   nové, vhodně navržené objekty zabudování podpory XML přímo do jazyku Visual Basic, podpora při kompilaci Dim doc As XElement = _ <rss><channel> <%= From post In MyData.Posts Take 5 Select _ <item><title><%= post.Title %></title></item> %> </channel></rss>  Technika dotazování shodná jako u LINQ to Objects  nové objekty jen lépe vyhovují modelu LINQ dotazů
  • LINQ to XML  Přístup k elementům v XML dokumentu <authors> <author name="Ludwig" surname="Wittgenstein"> <book title="Tractatus Logico-Philosophicus" /> <book title="Philosophical Investigations" /> </author> <author name="Rene" surname="Descartes"> <book title="Discourse on Method and the Meditations" /> <book title="Meditations and Other Metaphysical Writings" /> </author> </authors>      – vrací všechny elementy doc.Descendants("book") – vrací všechny knihy doc.Element("authors") – vrací kořenový element doc.Element("authors").Elements() – všechny autory el.Attribute("title“) – vrací hodnotu atributu doc.Descendants()
  • LINQ to XML – příklad dokumentu  Jednoduchý příklad XML dokumentu <Contacts> <Contact> <Name>Patrick Hines</Name> <Phone Type="Home">206-555-0144</Phone> <Phone Type="Work">425-555-0145</Phone> <Address> <Street>123 Main St</Street> <City>Mercer Island</City> <State>WA</State> <Postal>68042</Postal> </Address> </Contact> </Contacts>
  • LINQ to XML – předchozí generace  Postup pro vytvoření XML dokumentu v .NET 2.0 XmlDocument doc = new XmlDocument(); XmlElement name = doc.CreateElement("Name"); name.InnerText = "Patrick Hines"; XmlElement phone1 = doc.CreateElement("Phone"); phone1.SetAttribute("Type", "Home"); phone1.InnerText = "206-555-0144"; XmlElement phone2 = doc.CreateElement("Phone"); phone2.SetAttribute("Type", "Work"); phone2.InnerText = "425-555-0145"; XmlElement street1 = doc.CreateElement("Street1"); street1.InnerText = "123 Main St"; XmlElement city = doc.CreateElement("City"); city.InnerText = "Mercer Island"; XmlElement state = doc.CreateElement("State"); state.InnerText = "WA"; XmlElement postal = doc.CreateElement("Postal"); postal.InnerText = "68042"; XmlElement address = doc.CreateElement("Address"); address.AppendChild(street1); address.AppendChild(city); address.AppendChild(state); address.AppendChild(postal); XmlElement contact = doc.CreateElement("Contact"); contact.AppendChild(name); contact.AppendChild(phone1); contact.AppendChild(phone2); contact.AppendChild(address); XmlElement contacts = doc.CreateElement("Contacts"); contacts.AppendChild(contact); doc.AppendChild(contacts);
  • LINQ to XML – nová generace  Postup pro vytvoření XML dokumentu pomocí LINQ to XML XElement contacts = new XElement("Contacts", new XElement("Contact", new XElement("Name", "Patrick Hines"), new XElement("Phone", "206-555-0144", new XAttribute("Type", "Home") ), new XElement("Phone", "425-555-0145", new XAttribute("Type", "Work") ), new XElement("Address", new XElement("Street1", "123 Main St"), new XElement("City", "Mercer Island"), new XElement("State", "WA"), new XElement("Postal", "68042") ) ) );
  • LINQ to XML – XPath (porovnání)  XPath dotaz a jeho ekvivalent          child (the default axis) – XContainer.Elements Parent (..) – XObject.Parent attribute axis (@) – XElement.Attribute nebo Xelement.Attributes ancestor axis – XNode.Ancestors ancestor-or-self axis – XElement.AncestorsAndSelf descendant axis (//) – XContainer.Descendants nebo XContainer.DescendantNodes descendant-or-self – XElement.DescendantsAndSelf nebo XElement. DescendantNodesAndSelf following-sibling – XNode.ElementsAfterSelf nebo XNode.NodesAfterSelf preceding-sibling – XNode.ElementsBeforeSelf nebo XNode.NodesBeforeSelf
  • LINQ to SQL NorthwindDataContext db = new NorthwindDataContext(); var q = from c in db.Customers where c.Country == "UK" select new { Name = c.ContactName, c.City }  Používá dva klíčové principy LINQu    Dotazy jako konstrukce jazyka C# 3.0 Kód jako data (Lambda výrazy & Expression Trees) Jak to funguje?   Třídy popisují strukturu DB (NorthwindDataContext,…) Dotaz se překládá do jazyka SQL a pouští na SQL Serveru (využití rozhraní IQueryable<T>)
  • LINQ to SQL – struktura databáze  Model databáze lze vytvořit pomocí nástroje Object Relational Designer (O/R Designer)   existují další nástroje, jako např. SQLMetal, nebo lze popsat strukturu vlastním kódem podle přesných pravidel Vše je zapouzdřeno v potomku třídy DataContext  jsou případy, kdy je na místě uvažovat o zapouzdření vygenerovaného kódu pro omezení dostupných funkcí pro uživatele kódu či omezení potenciálních chyb, lepší podpoře transakcí atd.
  • LINQ to SQL – struktura databáze  Generuje se jedna třída pro každou tabulku   Atributy popisují mapování mezi objektem a databází „Column“ mapuje sloupeček v DB a vlastnost objektu [Table(Name="dbo.Customers")] public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged private string _CustomerID; { [Column(Storage = "_CustomerID", DbType = "NChar(5)")] public string CustomerID { get { /* ... */ } set { /* ... */ } } /* ... */ }
  • LINQ to SQL – struktura databáze  Třída „DataContext“ reprezentuje celou databázi   Obsahuje reprezentace tabulek (Table<Category>) Je možné nahradit implementaci základních operací [DatabaseAttribute(Name = "Northwind")] public partial class NwindDataContext : DataContext { public Table<Category> Categories { get { /* ... */ } } partial void InsertCategory(Category instance); partial void UpdateCategory(Category instance); partial void DeleteCategory(Category instance); }  Případně obsahuje metody pro volání uložených procedur
  • LINQ to SQL – parametrické dotazy 1) Skládání částí dotazu jako řetězců    Od Microsoftu (hledejte „Dynamic LINQ library“) Flexibilní, ale chybí kontrola v době kompilace Umožňuje následující zápis: var s = db.Products .Where("UnitPrice > 10.0 and CategoryID = 42"); var q = from p in s orderby p.ProductName select p;  Řetězce lze kombinovat se silně typovanými dotazy 2) Skládání lambda výrazů
  • LINQ to SQL – parametrické dotazy 1) Skládání částí dotazu jako řetězců 2) Skládání lambda výrazů   Hledejte „LINQ Queries at Runtime“ Zachová typovou kontrolu, ale více „myšlenkově náročné“, protože využívá pokročilejší vlastnosti lambda funkcí ConditionCombinator combineOr = (f, g) => (c) => f.Call(c) || g.Call(c); Expression<Func<Product, bool>> cond1 = (p) => p.UnitPrice > 10.0M; Expression<Func<Product, bool>> cond2 = (p) => p.CategoryID == 42; var q = from p in db.Products where combineOr.Call(cond1, cond2) orderby p.ProductName select p;
  • LINQ to SQL – kompilované dotazy  LINQ musí pokaždé přeložit „strom“ na SQL dotaz   Lze se tomu nějak vyhnout, optimalizovat to? Ano! LINQ umí tzv. „kompilované dotazy“ // Deklarace – lze např jako vlastnost ve třídě Func<NorthwindDataContext, string, IQueryable<Product>> ProductsByCategory; // Vytváření předkompilovaného dotazu ProductsByCategory = CompiledQuery.Compile( (NorthwindDataContext db, string catName) => from p in db.Products where p.Category.CategoryName == catName select p); // Volání předkompilovaného dotazu var q = ProductsByCategory(db, "Beverages");
  • LINQ to SQL – implicitní řetězení dotazů  Jednoduché načítání souvisejících dat    potřebujeme např. ke každému zpracovávanému zákazníkovi vždy znát i seznam jeho objednávek implicitní využívání cizích klíčů je schopné data zajistit, ale budeme mít množství dotazů směřujících do databáze existuje řešení Northwnd db = new Northwnd(@"c:northwnd.mdf"); DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Customer>(c => c.Orders); db.LoadOptions = dlo; var londonCustomers = from cust in db.Customers where cust.City == “London“ select cust; foreach (var custObj in londonCustomers) { if (custObj.Orders.Any()) { Console.WriteLine(custObj.CustomerID); } }
  • LINQ to SQL – implicitní filtrování dat  Jednoduché filtrování načítaných dat    pokud nás např. zajímají vždy jen objednávky neodeslané dnes nechceme tedy načítat vždy všechny objednávky, ani na všech místech v kódu uvádět stejnou podmínku existuje řešení Northwnd db = new Northwnd(@"c:northwnd.mdf"); DataLoadOptions dlo = new DataLoadOptions(); dlo.AssociateWith<Customer>(c => c.Orders.Where(p => p.ShippedDate != DateTime.Today)); db.LoadOptions = dlo; var custOrderQuery = from cust in db.Customers where cust.City == “London“ select cust;
  • LINQ to SQL – identita entit  Různé dotazy vrací „stejnou“ instanci   Stejný řádek podle primárního klíče v databázi „DataContext“ má cache a vrátí stejný .NET objekt! var db = new NwindDataContext(); var c1 = (from c in db.Categories where c.CategoryName = "Beverages" select c).First(); c1.CategoryName = "Drinks"; var c2 = (from c in db.Categories where c.CategoryID = 1 select c).First(); Console.WriteLine(c2.CategoryName);  Chování je možné pro zrychlení vypnout  …a pokud pouze načítáte data, pak je to výhodné: db.ObjectTrackingEnabled = false;
  • LINQ to SQL – modifikace dat  Přímá podpora pouze pomocí načtených instancí NwindDataContext db = new NwindDataContext(); var cat = (from c in db.Categories where c.CategoryID == 42 select c).First(); db.Categories.DeleteOnSubmit(cat); db.SubmitChanges();   „SubmitChanges“ ukládá změny do DB (nenastala-li kolize) Možnosti pro usnadnění a optimalizaci   Pomocí uložených procedur (není třeba nejprve načítat) Jako metody v „partial“ třídě „DataContext“
  • LINQ to SQL – modifikace dat  Příklad vkládání dat // Create a new Order object. Order ord = new Order { OrderID = 12000, ShipCity = "Seattle", OrderDate = DateTime.Now // … }; // Add the new object to the Orders collection. db.Orders.InsertOnSubmit(ord); // Submit the change to the database. db.SubmitChanges();
  • LINQ to SQL – transakční zpracování  Standardně používá „optimistic concurrency“     Při načtení se zapamatuje původní stav entit Načtené entity se upravují pouze v paměti Zavoláním „SubmitChanges()“ se změny zapisují do DB Před zápisem kontroluje, zda došlo ke změně a případná kolize způsobí výjimku NwindDataContext db = new NwindDataContext(); var cat = db.Categories.First(c => c.CategoryID == 1); cat.CategoryName = "Drinks"; db.SubmitChanges(); // LINQ zapíše změny do DB  Pomocí transakcí lze „pesimistic concurrency“
  • LINQ to SQL – transakční zpracování  Standardně používá „optimistic concurrency“  Pomocí transakcí lze „pesimistic concurrency“    Zamyká přistup k tabulce/řádku po dobu práce s ním Může nastat „deadlock“ (a jeden z čekajících je zrušen) např. pomocí: System.Transactions.TransactionScope NwindDataContext db = new NwindDataContext(); using (TransactionScope ts = new TransactionScope()) { var cat = db.Categories.First(c => c.CategoryID == 1); cat.CategoryName = "Drinks"; db.SubmitChanges(); // LINQ zapíše změny do DB ts.Complete(); // COMMIT transakce v DB }
  • LINQ to SQL – n-vrstvá architektura  LINQ lze obecně použít kdekoli, ale ...    Nepovolit programátorům napsat hloupost (např. stahování obsahu celé tabulky) Ale chceme flexibilitu při psaní dotazů Zapouzdříme vygenerovaný DataContext   Zpřístupníme pouze rozumné chování! Např.: Produkty lze vyhledávat pouze podle kategorie NorthwindDAL nd = new NorthwindDAL(); var productNames = from p in nd.GetProductsByCategory(beveragesId) select p.ProductName;
  • LINQ to SQL a ADO.NET  Využití jednoho připojení k databázi SqlConnection nwindConn = new SqlConnection(connString); nwindConn.Open(); Northwnd interop_db = new Northwnd(nwindConn); SqlTransaction nwindTxn = nwindConn.BeginTransaction(); // ... interop_db.Transaction = nwindTxn; // ... interop_db.SubmitChanges(); nwindTxn.Commit();
  • LINQ to DataSets  Podpora LINQ dotazů při práci s DataSety   Pomocí extension metod „Field“ a „AsEnumerable“ Existuje i varianta pro typované DataSety (generované třídy již podporují všechna potřebná rozhraní) using System.Data; // Potřebné extension metody! var q = from r in ds.Tables["Customers"].AsEnumerable() where r.Field<string>("City") == "London" select new { Name = r.Field<string>("Name"), City = r.Field<string>("City") };   Lze jednoduše řešit i případy Nullable-sloupců Pozn.: Extension metody umožňují přidat podporu pro LINQ k libovolným existujícím třídám!
  • LINQ to DataSets  Co když potřebujeme opakovat parametrické dotazy mnohokrát?   dotazy do číselníků v paměti atd. ADO.NET podporují DataView   LINQ dotaz nad DataSet není reprezentován jako DataView lze jednoduše řešit pomocí metody „AsDataView()“ var q = from row in data.AsEnumerable() orderby row.Field<DateTime>(“Date”) select row; DataView rowsByDate = q.AsDataView();  má své limitace (nullable-sloupce apod.)
  • Zdroje   MSDN Tomáš Petříček – Microsoft MVP pro C# Programátorské večery  V příštím semestru sledujte nástěnku. Uskuteční se přednáška na téma LINQ, kde se dostaneme i k praktickým ukázkám či podrobnějšímu vysvětlení.