![]() |
|
||||||
The Missing LINQ string[] stooges = { "Moe", "Larry", "Curly", "Shemp" }; With C# 3.0’s new query syntax, you can extract only strings with a length of 5, sort them alphabetically, and change the results to upper case: IEnumerable<string> query = In this snippet, from s in stooges indicates that you want to query the stooges collection and use s to represent each item in the sequence. The select clause determines the data you want returned and what shape it should take. Here we want to return each element converted to upper case. The where and orderby clauses, as you might guess, restrict the results to those with 5 characters and specify an ascending sort. Execution of the query is actually deferred until you iterate the query results, typically with a foreach statement, or by calling extension methods, such as ToArray or ToList, that perform the iteration internally (we’ll talk about extension methods in just a bit). The following statement triggers the query execution: foreach (string s in query) Console.WriteLine(s); This produces the following output: CURLY Behind the Magic: C# Language Enhancements namespace System.Linq As you can see, the method accepts a source of type IEnumerable<T> and a predicate of the Func generic delegate type. We can create an instance of the delegate as an anonymous method: Func<string, bool> predicate = delegate(string s) The Where method simply iterates over the source, returning only items that pass the predicate test. Because it’s defined as a static method, there’s nothing to prevent you from calling it directly, like so: IEnumerable<string> query = Enumerable.Where(stooges, predicate); However, because Where is defined as an extension method, we can invoke it using instance syntax (note, however, that it’s not really an instance method!): IEnumerable<string> query = stooges.Where(predicate); Extension methods are brought into scope when the namespace in which they are contained is imported with a using directive. However, they are only used if no matching methods with the same name and signature exist on the target type or its base classes. This lets you plug in your own query operators which take precedence over those in the System.Linq namespace. Although you can define the predicate as an anonymous method (or a standalone method for that matter), C# provides a much more compact syntax, called a lambda expression. If we were to re-write our anonymous method as a lambda expression and pass it as an argument, our call to Where would look like this (notice how the type of “s” is inferred and “return” is left out): IEnumerable<string> query = stooges.Where(s => s.Length == 5); The power of lambda expressions, however, is not just that they are compact (and hence more readable when passed as method parameters), but they can be compiled as either code or data. When assigned to the generic type Expression<T>, the compiler emits an expression tree representing the code rather than IL that would execute the code. Frameworks like LINQ to SQL can then analyze the expression tree to formulate SQL statements targeting a relational database. Bridging the Gap: LINQ to SQL, Linq to XML NorthwindDataContext db = new NorthwindDataContext(); IEnumerable<Product> prodQuery = The NorthwindDataContext class derives from DataContext, which does the heavy lifting to convert the query expression into SQL, execute it against the database, and return the results as a sequence of Product objects. Where, might you ask, are these classes defined? It just so happens that Visual Studio 2008 comes with special tool support for LINQ to SQL, including a class designer (which you get when adding a “LINQ to SQL Classes” item to a project). The designer generates the NorthwindDataContext and Product classes when you drag the Products table from a data connection in the Server Explorer onto the class designer. If you bring over multiple tables, relations between the tables are reflected in the class diagram and become object properties in the designer-generated code.
Notice how the where clause in our query references the CategoryName property of the Category class, which is shown to be a property of the Product class. When you execute this query, LINQ to SQL generates a SQL statement that includes a JOIN on the Products and Categories tables. The join is performed by SQL Server, which makes for efficient query execution. You can see this take place by setting the Log property of the data context to dump output to the console window or a text file. SELECT * FROM [dbo].[Products] AS [t0] LINQ to SQL also includes support for tracking changes to in-memory objects, then posting those changes back to the database, while at the same time maintaining concurrency control. (If you like, you can also specify stored procedures for the updates.) For example, we can store our product list in a local collection, change the unit price of an item, then call SubmitChanges to persist the new data back to SQL Server. List<Product> products = prodQuery.ToList(); Product chai = (from p in products chai.UnitPrice = 20; db.SubmitChanges(); The ORM functionality of LINQ to SQL is somewhat limited (for example, many-to-many relationships aren’t fully supported and it only works with SQL Server). But the power of LINQ really shines when combining LINQ to Objects, LINQ to SQL and LINQ to XML. We can, for instance, take our list of beverages, sort them, and save them as an XML file. IEnumerable<XElement> xmlQuery = XElement bevXml = new XElement("Beverages", xmlQuery); bevXml.Save("beverages.xml"); Notice how this code, unlike the DOM API, is element-centric, as opposed to document-centric, and that there’s no need for XPath query strings. Nice. The beverages.xml file looks like this: <?xml version="1.0" encoding="utf-8"?> Time to LINQ Up! |
|||||||
![]() For more information email: onsites@develop.com or call 800.699.1932 |
|||||||
|
|||||||
NEW- .NET: MyTeam Custom Editions
Start customizing your course today with a few simple answers. We'll recommend a custom edition that is designed for the experience level of your team. Then you can tailor the course to best support the application you're building.
|
|||||||
|
|||||||
Essential .NET 2.0 | |||||||