C# 3.0 & LINQ
Raimond Brookman – IT Architecthttp://blogs.infosupport.com/raimondb
Outline
- Linq Project- DLinq- XLinq- C# 3.0 Language Enhancements
Problem:Problem:Data != ObjectsData != Objects
Service based Solution
Customer Mgt Customer Mgt ServiceService
(HTTP + XML)(HTTP + XML)
WebWebApplicationApplication
Order MgtOrder MgtWSWS
Order ProcessingOrder ProcessingWSWS
ORM
Xml R/W
Databound grid
BR Check
TransformMsg
<book> <title/> <author/> <year/> <price/></book>
XML ConfigXML Config
XmlRead
The LINQ Project
StandardStandardQueryQuery
OperatorsOperators
ObjectsObjects
DLinqDLinq(ADO.NET)(ADO.NET)
XLinqXLinq(System.Xml)(System.Xml)
<book> <title/> <author/> <year/> <price/></book>
XMLXML
.NET Language Integrated Query.NET Language Integrated Query
C# 3.0C# 3.0 VB 9.0VB 9.0 Others…Others…
SQLSQL WinFWinFSS
Service based Solution with LINQ
Customer Mgt Customer Mgt ServiceService
(HTTP + XML)(HTTP + XML)
WebWebApplicationApplication
Order MgtOrder MgtWSWS
Order ProcessingOrder ProcessingWSWS
ORM
Xml R/W
Databound grid
BR Check
TransformMsg
<book> <title/> <author/> <year/> <price/></book>
XML ConfigXML Config
XmlRead
DLINQ
O-LINQ
O-LINQXLINQ
XLINQ
O-LINQ
LINQ Style programming
var contacts =var contacts = from c in customersfrom c in customers where c.State == "WA"where c.State == "WA" select new { c.Name, c.Phone };select new { c.Name, c.Phone };
class Contact { … };class Contact { … };List<Contact> contacts = new List<Contacts>();List<Contact> contacts = new List<Contacts>();foreach(Customer c in customers) foreach(Customer c in customers) {{
if(c.State == “WA”) if(c.State == “WA”) {{ Contact ct = new Contact();Contact ct = new Contact(); ct.Name = c.Name;ct.Name = c.Name; ct.Phone = c.Phone;ct.Phone = c.Phone; contacts.Add(ct);contacts.Add(ct);}}
}}
Query Expressions
Language integrated query syntax
fromfrom idid inin sourcesource{ { fromfrom idid inin sourcesource | | wherewhere conditioncondition } }[ [ orderbyorderby orderingordering, , orderingordering, … ], … ]selectselect exprexpr | | groupgroup exprexpr byby keykey[ [ intointo idid queryquery ] ]
Standard Query Operators
RestrictionRestriction WhereWhereProjectionProjection Select, SelectManySelect, SelectManyOrderingOrdering OrderBy, ThenByOrderBy, ThenByGroupingGrouping GroupByGroupByQuantifiersQuantifiers Any, AllAny, AllPartitioningPartitioning Take, Skip, TakeWhile, SkipWhileTake, Skip, TakeWhile, SkipWhileSetsSets Distinct, Union, Intersect, ExceptDistinct, Union, Intersect, ExceptElementsElements First, FirstOrDefault, ElementAtFirst, FirstOrDefault, ElementAtAggregationAggregation Count, Sum, Min, Max, AverageCount, Sum, Min, Max, AverageConversionConversion ToArray, ToList, ToDictionaryToArray, ToList, ToDictionaryCastingCasting OfType<T>OfType<T>
DLinq For Relational Data
SqlConnection c = new SqlConnection(…);SqlConnection c = new SqlConnection(…);c.Open();c.Open();SqlCommand cmd = new SqlCommand(SqlCommand cmd = new SqlCommand( @"@"SELECT c.Name, c.PhoneSELECT c.Name, c.Phone FROM Customers cFROM Customers c WHERE c.City = @p0WHERE c.City = @p0");");cmd.Parameters.AddWithValue("cmd.Parameters.AddWithValue("@p0@p0", ", "London“);"London“);DataReader dr = c.Execute(cmd);DataReader dr = c.Execute(cmd);while (dr.Read()) {while (dr.Read()) { string name = dr.GetString(0);string name = dr.GetString(0); string phone = dr.GetString(1);string phone = dr.GetString(1); DateTime date = dr.GetDateTime(2);DateTime date = dr.GetDateTime(2);}}dr.Close();dr.Close();
Accessing data todayAccessing data todayQueries in Queries in
quotesquotes
Loosely bound Loosely bound argumentsarguments
Loosely typed Loosely typed result setsresult sets
No compile No compile time checkstime checks
public class Customer { … }public class Customer { … }
public class Northwind: DataContextpublic class Northwind: DataContext{{ public Table<Customer> Customers;public Table<Customer> Customers; … …}}
Northwind db = new Northwind(…);Northwind db = new Northwind(…);var contacts =var contacts = from c in db.Customersfrom c in db.Customers where c.City == "London"where c.City == "London" select new { c.Name, c.Phone };select new { c.Name, c.Phone };
DLinq For Relational DataAccessingAccessing data with DLinqdata with DLinq
Classes Classes describe datadescribe data
Strongly typed Strongly typed connectionconnection
Integrated Integrated query syntaxquery syntax
Strongly typed Strongly typed resultsresults
Tables are Tables are like collectionslike collections
DLinq For Relational Data
Language integrated data accessMaps tables and rows to classes and objectsBuilds on ADO.NET and .NET Transactions
MappingEncoded in attributesRelationships map to properties
PersistenceAutomatic change trackingUpdates through SQL or stored procedures
XLinq For XML Data
XmlDocument doc = new XmlDocument();XmlDocument doc = new XmlDocument();XmlElement contacts = doc.CreateElement("contacts");XmlElement contacts = doc.CreateElement("contacts");foreach (Customer c in customers)foreach (Customer c in customers) if (c.Country == "USA") {if (c.Country == "USA") { XmlElement e = doc.CreateElement("contact");XmlElement e = doc.CreateElement("contact"); XmlElement name = doc.CreateElement("name");XmlElement name = doc.CreateElement("name"); name.InnerText = c.CompanyName;name.InnerText = c.CompanyName; e.AppendChild(name);e.AppendChild(name); XmlElement phone = doc.CreateElement("phone");XmlElement phone = doc.CreateElement("phone"); phone.InnerText = c.Phone;phone.InnerText = c.Phone; e.AppendChild(phone);e.AppendChild(phone); contacts.AppendChild(e);contacts.AppendChild(e); }}doc.AppendChild(contacts);doc.AppendChild(contacts);
Programming XML todayProgramming XML today
<contacts> <contact> <name>Great Lakes Food</name> <phone>(503) 555-7123</phone> </contact> …</contacts>
Imperative Imperative modelmodel
Document Document centriccentric
No integrated No integrated queriesqueries
Memory Memory intensiveintensive
XLinq For XML Data
XElement contacts = new XElement("contacts",XElement contacts = new XElement("contacts", from c in customersfrom c in customers where c.Country == "USA"where c.Country == "USA" select new XElement("contact",select new XElement("contact", new XElement("name", c.CompanyName),new XElement("name", c.CompanyName), new XElement("phone", c.Phone)new XElement("phone", c.Phone) ))););
Programming XML with XLinqProgramming XML with XLinq Declarative Declarative modelmodel
ElementElementcentriccentric
Integrated Integrated queriesqueries
Smaller and Smaller and fasterfaster
XLinq For XML Data
Language integrated query for XMLExpressive power of XPath / XQueryBut with C# or VB as programming language
Leverages experience with DOMElement centric, not document centricFunctional constructionText nodes are just stringsSimplified XML namespace supportFaster and smaller
C# 3.0 Design Goals
• Integrate objects, relational, and XML
• Build on foundation laid in C# 1.0 and 2.0
• Run on the .NET 2.0 CLR
• Remain 100% backwards compatible
C# 3.0 Language Innovationsvar contacts =var contacts = from c in customersfrom c in customers where c.State == "WA"where c.State == "WA" select new { c.Name, c.Phone };select new { c.Name, c.Phone };
var contacts =var contacts = customerscustomers .Where(c => c.State == "WA").Where(c => c.State == "WA") .Select(c => new { c.Name, .Select(c => new { c.Name, c.Phone });c.Phone });Extension Extension
methodsmethods
Lambda Lambda expressionsexpressions
Query Query expressionsexpressions
Object Object initializersinitializers
Anonymous Anonymous typestypes
Local variable Local variable type inferencetype inference
Queries Through APIspublic class List<T>public class List<T>{{ public List<T> Where(Func<T, bool> predicate) { … }public List<T> Where(Func<T, bool> predicate) { … } public List<S> Select<S>(Func<T, S> selector) { … }public List<S> Select<S>(Func<T, S> selector) { … } … …}}
List<Customer> customers = GetCustomerList();List<Customer> customers = GetCustomerList();List<string> contacts =List<string> contacts = customers.Where(c => c.State == "WA").Select(c => customers.Where(c => c.State == "WA").Select(c => c.Name);c.Name);
Query operators Query operators are just methodsare just methods
But what about But what about other types?other types?Declare operators Declare operators
in all collections?in all collections?What about What about
arrays?arrays?
Methods compose Methods compose to form queriesto form queries
Queries Through APIspublic static class Sequencepublic static class Sequence{{ public static IEnumerable<T> Where<T>(IEnumerable<T> public static IEnumerable<T> Where<T>(IEnumerable<T> source,source, Func<T, bool> predicate) { … }Func<T, bool> predicate) { … }
public static IEnumerable<S> Select<T, S>(IEnumerable<T> public static IEnumerable<S> Select<T, S>(IEnumerable<T> source,source, Func<T, S> selector) { … }Func<T, S> selector) { … } … …}} Customer[] customers = GetCustomerArray();Customer[] customers = GetCustomerArray();
IEnumerable<string> contacts = Sequence.Select(IEnumerable<string> contacts = Sequence.Select( Sequence.Where(customers, c => c.State == Sequence.Where(customers, c => c.State == "WA"),"WA"), c => c.Name);c => c.Name);
Query operators Query operators are static methodsare static methods
Huh?Huh?
Want methods on Want methods on IEnumerable<T>IEnumerable<T>
namespace System.Querynamespace System.Query{{ public static class Sequencepublic static class Sequence {{ public static IEnumerable<T> Where<T>(this IEnumerable<T> public static IEnumerable<T> Where<T>(this IEnumerable<T> source,source, Func<T, bool> predicate) { … }Func<T, bool> predicate) { … }
public static IEnumerable<S> Select<T, S>(this public static IEnumerable<S> Select<T, S>(this IEnumerable<T> source,IEnumerable<T> source, Func<T, S> selector) { … }Func<T, S> selector) { … } … … }}}}
Solution: Extension Methods
using System.Query;using System.Query;
ExtensionExtensionmethodsmethods
IEnumerable<string> contacts =IEnumerable<string> contacts = customers.Where(c => c.State == "WA").Select(c => customers.Where(c => c.State == "WA").Select(c => c.Name);c.Name);
Brings extensions Brings extensions into scopeinto scope
obj.Foo(x, y)obj.Foo(x, y)
XXX.Foo(obj, x, y)XXX.Foo(obj, x, y)
IntelliSense!IntelliSense!
Local Variable Type Inference
int i = 5;int i = 5;string s = "Hello";string s = "Hello";double d = 1.0;double d = 1.0;int[] numbers = new int[] {1, 2, 3};int[] numbers = new int[] {1, 2, 3};Dictionary<int,Order> orders = new Dictionary<int,Order> orders = new Dictionary<int,Order>();Dictionary<int,Order>();var i = 5;var i = 5;var s = "Hello";var s = "Hello";var d = 1.0;var d = 1.0;var numbers = new int[] {1, 2, 3};var numbers = new int[] {1, 2, 3};var orders = new Dictionary<int,Order>();var orders = new Dictionary<int,Order>();
““var” means same var” means same type as initializertype as initializer
Anonymous Typespublic class Customerpublic class Customer{{ public string Name;public string Name; public Address Address;public Address Address; public string Phone;public string Phone; public List<Order> Orders;public List<Order> Orders; … …}}
public class Contactpublic class Contact{{ public string Name;public string Name; public string Phone;public string Phone;}}
Customer c = GetCustomer(…);Customer c = GetCustomer(…);Contact x = new Contact { Name = c.Name, Phone = Contact x = new Contact { Name = c.Name, Phone = c.Phone };c.Phone };
Customer c = GetCustomer(…);Customer c = GetCustomer(…);var x = new { c.Name, c.Phone };var x = new { c.Name, c.Phone };
Customer c = GetCustomer(…);Customer c = GetCustomer(…);var x = new { Name = c.Name, Phone = c.Phone };var x = new { Name = c.Name, Phone = c.Phone };
class ???class ???{{ public string Name;public string Name; public string Phone;public string Phone;}}
Projection style Projection style initializerinitializer
var contacts =var contacts = from c in customersfrom c in customers where c.State == "WA"where c.State == "WA" select new { c.Name, c.Phone };select new { c.Name, c.Phone };
Anonymous Types
var contacts =var contacts = customers.customers. .Where(c => c.State == "WA“).Where(c => c.State == "WA“) .Select(c => new { c.Name, .Select(c => new { c.Name, c.Phone });c.Phone });
class ???class ???{{ public string Name;public string Name; public string Phone;public string Phone;}}
IEnumerable<???>IEnumerable<???>
foreach (var c in contacts) {foreach (var c in contacts) { Console.WriteLine(c.Name);Console.WriteLine(c.Name); Console.WriteLine(c.Phone);Console.WriteLine(c.Phone);}}
??????
public delegate bool Predicate<T>(T obj);public delegate bool Predicate<T>(T obj);
public class List<T>public class List<T>{{ public List<T> FindAll(Predicate<T> test) public List<T> FindAll(Predicate<T> test) { … }{ … } … …}}
Lambda Expressions
List<Customer> customers = List<Customer> customers = GetCustomerList();GetCustomerList();
List<Customer> x = customers.FindAll(List<Customer> x = customers.FindAll( delegate(Customer c) { return c.State == delegate(Customer c) { return c.State == "WA"; }"WA"; }););List<Customer> x = customers.FindAll(c => c.State List<Customer> x = customers.FindAll(c => c.State == "WA");== "WA");
ExplicitlyExplicitlytypedtyped
Statement Statement contextcontext
ImplicitlyImplicitlytypedtyped
Expression Expression contextcontext
Expression Treespublic class Northwind: DataContextpublic class Northwind: DataContext{{ public Table<Customer> public Table<Customer> Customers;Customers; public Table<Order> Orders;public Table<Order> Orders; … …}} Northwind db = new Northwind(…);Northwind db = new Northwind(…);
var query = from c in db.Customers where c.State == "WA" var query = from c in db.Customers where c.State == "WA" select c;select c;
Northwind db = new Northwind(…);Northwind db = new Northwind(…);var query = db.Customers.Where(c => c.State == var query = db.Customers.Where(c => c.State == "WA");"WA");
How does this How does this become SQL ?become SQL ?
public class Table<T>: IEnumerable<T>public class Table<T>: IEnumerable<T>{{ public Table<T> Where(Expression<Func<T, bool>> public Table<T> Where(Expression<Func<T, bool>> predicate);predicate); … …}}
Method asks for Method asks for expression treeexpression tree
System.Expressions.System.Expressions.Expression<T>Expression<T>
Expression TreesCode as Data
Func<Customer, bool> test = c => c.State == Func<Customer, bool> test = c => c.State == "WA";"WA";
Expression<Func<Customer, bool>> test = c => c.State Expression<Func<Customer, bool>> test = c => c.State == "WA";== "WA";ParameterExpression c =ParameterExpression c = Expression.Parameter(typeof(Customer), "c");Expression.Parameter(typeof(Customer), "c");Expression expr =Expression expr = Expression.EQ(Expression.EQ( Expression.Property(c, Expression.Property(c, typeof(Customer).GetProperty("State")),typeof(Customer).GetProperty("State")), Expression.Constant("WA")Expression.Constant("WA") ););Expression<Func<Customer, bool>> test =Expression<Func<Customer, bool>> test = Expression.Lambda<Func<Customer, bool>>(expr, c);Expression.Lambda<Func<Customer, bool>>(expr, c);
stringConstant :Constant
Value = "WA"
stateProperty :Property
PropertyName = "State"
equality :EQ
customerParam :ParameterExpression
Type = typeof(Customer)Name = c
test :Lambda
righttarget left
parameterexpression
Benefits Of LINQ
Unified querying of objects, relational, XML
Type checking and IntelliSense for queries
SQL and XQuery-like power in C# and VB
Extensibility model for languages / APIs
Call to Action
- Get VS 2005- Download LINQ preview
http://msdn.microsoft.com/netframework/future/linq/
Play Around & See the power!
Q & A