1 / 36

LinQ Introduction

LinQ Introduction. Outline. Goals of LinQ Anatomy of a LinQ query More expression examples LinQ to Objects LinQ to XML LinQ to SQL. Goals of LinQ. Integrate data queries into .Net languages

tilden
Download Presentation

LinQ Introduction

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. LinQ Introduction

  2. Outline • Goals of LinQ • Anatomy of a LinQ query • More expression examples • LinQ to Objects • LinQ to XML • LinQ to SQL

  3. Goals of LinQ • Integrate data queries into .Net languages • Before C# 3.0 you could use delegates, extension methods, anonyous methods and Visitor Pattern to make something similar to LinQ. • But the syntax is messy and key points, eg. selection criteria, are not easy to read.

  4. Goals of LinQ • Provide a standardized way to query data • Challenges: • Different data types • Different data representations (xml, sql, objects) • Data organization • Hierarchical – xml (and object) • Relational – sql • Before LinQ you should use different api’s for accessing databases, objects and xml • LinQ provides one single way (nearly) to access it all • LinQ works on collections that implements IEnumerable<T> • (the .Net language must therefore support generics)

  5. Anatomy of a LinQ query • An example: string[] characters = { "Donald", "Mickey", "Goofy", "Minnie", "Daisy", "Scrooge" }; IEnumerable<string> query = from c in characters where c.StartsWith("M")!=true orderby c descending select c; foreach(string s in query) Console.WriteLine(s); • The collection is here a simple string array • But the same query will run for more complex objects, SQL, XML etc.

  6. Demo • With objects • After demo, note the following: • Intellisense • Static type checking

  7. Query Expressions • Types of expressions • Filtering • e.g. Where • Projections • e.g. Select • Joining • e.g. Join • Partitioning • e.g Skip and Take • Ordering • e.g OrderBy • Aggregation • e.g. Count and Sum

  8. Providers • The same expresions works on different kinds of data • This is done by accessing a provider • A LinQ provider is a gateway to a querable type. • There are several builtin providers • Objects • SQL • XML • Active Directory • PLINQ (Parallel processing) • Etc. • And many custom providers too: • LinQ to Amazon • LinQ to Twitter • Etc.

  9. How are people in Aalborg ? • Twitter demo • Get LinqToTwitter here: http://linqtotwitter.codeplex.com/ var twitterCtx = newTwitterContext(); .. var queryResults = from search in twitterCtx.Search where search.Type == SearchType.Search && search.Attitude == Attitude.Positive && search.GeoCode == "57.028811,9.917771,25km" select search; foreach (SearchEntry entry in srch.Results) Console.WriteLine(entry.Text);

  10. Deferred Execution • Normally the query is not executed before the result is needed • This is when only lazy operators (where, orderby...) are used. • When busy operators are used, the query is executed immediately (count, average) var adults = from p in personList where p.Age > 18 orderby p.Age select (p.FirstName + " " + p.LastName); Console.WriteLine(adults.Count()); personList.Add(new Person { FirstName = “Ib", LastName = “Madsen", Age = 35 }); foreach (var p in adults) { Console.WriteLine(p.ToString()); }

  11. Composed Queries • A composed query is a query that uses another query. • In behind LinQ will make new query that is optimized for the given data store (objects, sql, xml...) var adults = from p in personList where p.Age > 18 orderby p.Age select (p.FirstName + " " + p.LastName); ..... var query = from p in adults where p.StartsWith("B") select p; foreach (var p in query) Console.WriteLine(p);

  12. Encapsulate Query • It is not possible directly to return an anonymous type • And it wouldn’t be nice either  • Therefore it not is possible to return a query if is declared as var • The nice way here is to declare the query as an IEnumerable<type> and return that. • If the query is a join or a projection etc. then make a class that maps the output from ‘select’ and return a collection of objects of that class

  13. Collections of objects • We already seen how to access a collection of objectsthis is called LinQ to objects • LinQ to objects is a good alternative to foreach and other iterations

  14. Custom providers • And we have seen use of a custom provider to access a webservice. • If it is a plain webservice that returns a collection, then we could have accessed that with LinQ to objects

  15. In the next part, we will see how to access XML and SQLServer.

  16. LinQ to XML • Uses the System.Xml.Linq namespace • Is somewhat different from other xml api’s • The XElement class is the key class. • When instanizing a XElement you can generate the whole document in the constructor • XElement doc = • new XElement("Inventory", • new XElement("Car", new XAttribute("ID","1000"), • new XElement("Color", "Red"), • new XElement("Make", "Ford")) • ); <Inventory> <CarID="1000"> <Color>Red</Color> <Make>Ford</Make> </Car> </Inventory>

  17. Use LinQ to generate XML XElement personDoc =newXElement("People", from c in personList orderby c.LastName selectnewXElement("Person", newXAttribute("Age", c.Age), newXElement("FirstName", c.FirstName), newXElement("LastName", c.LastName) )); <People> <PersonAge="2"> <FirstName>Caroline</FirstName> <LastName>Bendtsen</LastName> </Person> <PersonAge="67"> <FirstName>Bjarne</FirstName> <LastName>Hansen</LastName> </Person> <PersonAge="13"> ...

  18. Use LinQ to search in XML XElement doc = MakeXElementFromList(); var query = from p in doc.Elements("Person") whereConvert.ToInt32(p.Attribute("Age").Value) < 40 select p; foreach (var p in query) Console.WriteLine(p.Value);

  19. LinQ to SQL • LinQ accesses the sql db through a datacontext class • The class can be created with a wizard in VisualStudio,where you select which tables to access • Only SQLServer is supported from Microsoft • But dbms vendors like Oracle are also providing support for LinQ. (haven’t tested it myself). • An (better?) alternative is to use the Entity Framework

  20. Use the wizard to create the DataContext class • Add a new item to the project using the ”LINQ to SQL classes” template. • Select the database and the tables that shall be available

  21. Select the tables • Note that wizard knows the carnalities

  22. Using LinQ to SQL • Select orders from a certain customer NorhwindDataContext dc =new NorhwindDataContext(); var orders = from o in dc.Orders where o.CustomerID == "ALFKI" orderby o.OrderDate select o.OrderID; foreach (var o in orders) Console.WriteLine(o); SELECT [t0].[OrderID] FROM [dbo].[Orders] AS [t0] WHERE [t0].[CustomerID] = @p0 ORDER BY [t0].[OrderDate]

  23. A join • Write products that the customer has brought var orders = from o in dc.Order_Details join p in dc.Products on o.ProductID equals p.ProductID where o.Order.CustomerID == "ALFKI" orderby o.Order.OrderDate selectnew { product = p.ProductName, orderDate = o.Order.OrderDate }; foreach (var p in orders) Console.WriteLine("{0:dd-MM-yyyy}: {1}", (DateTime)p.orderDate, p.product); {SELECT [t1].[ProductName] AS [product], [t2].[OrderDate] AS [orderDate] FROM [dbo].[Order Details] AS [t0] INNER JOIN [dbo].[Products] AS [t1] ON [t0].[ProductID] = [t1].[ProductID] INNER JOIN [dbo].[Orders] AS [t2] ON [t2].[OrderID] = [t0].[OrderID] WHERE [t2].[CustomerID] = @p0 ORDER BY [t2].[OrderDate] }

  24. Join • Join is similar to Inner Join in SQL • That means that it is the intersection between two sequences • The inner sequence is a keyed collection, that makes it a lot faster than a subquery (or traversing in a nested loop) • Note that it uses Equals instead of == (remember the difference?)

  25. Group • Group transforms a sequence into a sequence of groups that contains a subsequence var products = from p indc.Products group p byp.Category.CategoryName; foreach (var group in products) { Console.WriteLine("\nCategory: {0}", group.Key); foreach (var product in group) Console.WriteLine(product.ProductName);

  26. Use objects as keys • It is possible to use objects as keys. • It can be of an anonymous type or of a defined class var products = from p indc.Products group p bynew { cname = p.Category.CategoryName, cid = p.Category.CategoryID } intoproductCategories orderbyproductCategories.Key.cid selectproductCategories; foreach (var group in products) { Console.WriteLine("\nID: {0} Category: {1}",group.Key.cid,group.Key.cname); foreach(var product in group) Console.WriteLine(product.ProductName); }

  27. Group into • Group will end the query. Use ‘Into’ to continue the query var products = from p indc.Products group p byp.Category.CategoryNameintoproductCategories orderbyproductCategories.Key selectproductCategories; foreach (var group in products) { Console.WriteLine("\nCategory: {0}", group.Key); foreach (var product in group) Console.WriteLine(product.ProductName);

  28. Grouping and projecting • Make a projection on the content of the group var products = from p in dc.Products group p by p.Category into productCategories where productCategories.Count() < 8 orderby productCategories.Key.CategoryName selectnew { cname = productCategories.Key.CategoryName, count = productCategories.Count() }; foreach (var group in products) { Console.WriteLine("Category: {0}, Count: {1}", group.cname,group.count); }

  29. Nested queries • Nested queries are similar to nested SELECT in SQL. • But be careful: O(n2) var products = from p in dc.Products where p.CategoryID == (from c in dc.Categories where c.CategoryName == "Seafood" select c).First().CategoryID select p; foreach (var p in products) { Console.WriteLine("Category: {0}, Product: {1}", p.Category.CategoryName, p.ProductName); }

  30. Let keyword • Reuse expressions var products = from p in dc.Products group p by p.Category into productCategories let upperName= productCategories.Key.CategoryName.ToUpper() where productCategories.Count() < 8 orderby upperName selectnew { cname = upperName, count = productCategories.Count() }; foreach (var group in products) { Console.WriteLine("Category: {0}, Count: {1}", group.cname,group.count); }

  31. A few words on operators • The LinQ operators are implemented with extension methods (recall the .Where method) • You can define your own operator by defining an extension method • And you can overwrite the existing operators • But be careful: • The operator should still do the same sort of things as it was originally intended for.E.g. the Where operator should still be a filter operator • If the operator is not an aggregator it should be lazy to support deferred execution. • Use ”yield” keyword when returning items from lazy operators

  32. Define a contrary version of Where • The extension method must be in another namespace using System; usingSystem.Collections.Generic; usingLinQExamples; namespaceMaryTheContrary//Rasmus Modsat { publicstaticclassExtensionMethods { publicstaticIEnumerable<Person> Where(thisIEnumerable<Person> sequence, Func<Person, bool> predicate) { foreach (Person p in sequence) { if (!predicate(p)) //Contrary yieldreturn p; } } }}

  33. Use of the contrary ‘where’ • The compiler differs between different where’s by the namespace. So you must use ‘using <the namespace> usingMaryTheContrary; .... IEnumerable<Person> nonAdults = from p inpersonList wherep.Age > 18 orderbyp.Age select p; foreach(Person p innonAdults) Console.WriteLine(“First Name: {0} Age:{1}",p.FirstName,p.Age);

  34. LINQPad • Utility for interactively search with LinQ • You can get it here: http://www.linqpad.net/

  35. Exercise 1 • You can get the processes that runs on the machine withIEnumerable<Process> System.Diagnostics.Process.GetProcesses() • The Process object has several properties, e.g. • ProcessName returns the name of the process • WorkingSet64 returns the allocated memory in bytes • TotalProccessorTime return the CPU time that has been used • TODO: • Write and test a LinQ query that returns the processes that has allocated more than 50mb (1mb=10124*1024 bytes) and ordered by process name. The allocated memory should be outputted in mb. • Do the same in a foreach without LinQ.

  36. Exercise 2, advanced • Continued from exercise 1. • You will get an exception if you try to get TotalProcessorTime on a process that you do not own, e.g. a system process • And it not possible to filter those processes out ! • A workaround could be like this: IEnumerable<Process> processes = Process.GetProcesses(); foreach(Process p in processes){ try { Console.WriteLine("Process Name: {0} Time: {1}", p.ProcessName, p.TotalProcessorTime); } catch(Exception e){ Console.WriteLine("Process Name: {0} Time: {1}", p.ProcessName, null); }} • TODO: Override “select” so it inserts null’s for values that are not available. Test it in a LinQexpression • (To get it work: Remove “Using System.Linq”, and also implement “Where”)

More Related