LINQ:
Language Integrated Query
ST Colloquium, 2008-05-15
Tom Lokhorst
Brief example
Brief example
int[] nrs = {2, 3, 9, 1, 21, 3, 42};
Brief example
int[] nrs = {2, 3, 9, 1, 21, 3, 42};
var q = from n in nrs
where n < 5
select n * n;
Brief example
int[] nrs = {2, 3, 9, 1, 21, 3, 42};
var q = from n in nrs
where n < 5
select n * n;
foreach (var i in q)
{
[Link](i);
}
Brief example
int[] nrs = {2, 3, 9, 1, 21, 3, 42};
var q = from n in nrs
where n < 5
select n * n;
LINQ
foreach (var i in q)
{
[Link](i);
}
Overview
The problem space
LINQ in .NET 3.5
Deconstructing expressions
Usages of LINQ
Comparisons with other stuff
Circles, Triangles and
Rectangles
Circles, Triangles and
Rectangles
Circles, Triangles and
Rectangles
Business software deals with
lots of different types of data:
Objects
Tree structures (XML)
Relational
Assignment
A web server should show a list of the top 5
memory-intensive processes.
Per process, show its name, and a description.
There is a SQL database with descriptions for
programs.
The list should be in RSS format.
A bit of History
A bit of History
.NET 1.0 released early 2002
CLR 1.0, C# 1.0, VB 7.0
Delegates: managed function pointers
A bit of History
.NET 1.0 released early 2002
CLR 1.0, C# 1.0, VB 7.0
Delegates: managed function pointers
.NET 2.0 released late 2005
CLR 2.0, C# 2.0, VB 8.0
Generics, iterators, anonymous delegates
A bit of History
.NET 1.0 released early 2002
CLR 1.0, C# 1.0, VB 7.0
Delegates: managed function pointers
.NET 2.0 released late 2005
CLR 2.0, C# 2.0, VB 8.0
Generics, iterators, anonymous delegates
.NET 3.5 released late 2007
CLR 2.0, C# 3.0, VB 9.0
Lambda expressions, local type inferencing,
extension methods, LINQ
LINQ in .NET 3.5
Libraries
LINQ to Objects
LINQ to XML
LINQ to SQL
Language enhancements
Lambda expressions
Query syntax
Compiler enhancements
Expression trees
LINQ to Objects
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
var q = from n in nrs
where n < 5
select n * n;
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
IEnumerable<int> q = from n in nrs
where n < 5
select n * n;
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
IEnumerable<int> q =
[Link]<int>(n => n < 5)
.Select<int, int>(n => n * n);
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
IEnumerable<float> q =
[Link]<int>(n => n < 5)
.Select<int, float>(n => n * 0.5F);
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
IEnumerable<float> q =
[Link]<int, float>(
[Link]<int>(nrs, n => n < 5),
(n => n * 0.5F));
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
IEnumerable<float> q =
[Link]<int, float>(
[Link]<int>(nrs, n => n < 5),
(n => n * 0.5F));
public static IEnumerable<T>
Where<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
...
}
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
IEnumerable<float> q =
[Link]<int, float>(
[Link]<int>(nrs, n => n < 5),
(n => n * 0.5F));
public static IEnumerable<T>
Where<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
foreach (var elem in source)
if (predicate(elem))
yield return elem;
}
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
IEnumerable<float> q =
[Link]<int, float>(
[Link]<int>(nrs, n => n < 5),
(n => n * 0.5F));
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
2.0
IEnumerable<float> q =
[Link]<int, float>(
[Link]<int>(nrs,
delegate(int n){ return n < 5; }),
delegate(int n){ return n * 0.5F;}
);
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
1.0*
IEnumerable<float> q =
[Link]<int, float>(
[Link]<int>(nrs,
new Func<int, bool>(LessThanFive)),
new Func<int, float>(TimesHalf)
);
bool LessThanFive(int n) { return n < 5; }
float TimesHalf(int n) { return n * 0.5F; }
Eating the sugar
int[] nrs = {2, 3, 9, 1, 21, 3, 42}; C#
3.0
var q = from n in nrs
where n < 5
select n * n;
LINQ to Objects
Query comprehenssions
More syntax; orderby, groupby, join
Works on you data structures
IEnumerable<T>
Implement you own Where<T>, Select<T>
More library functions
LINQ to XML
Dealing with angle brackets
LINQ to XML is a replacement for the
W3C Document Object Model, because:
Its old
Its ugly
Its impractical
New API, all library: [Link]
Document Object Model
Imperative API
Document-centric
Weird data types
Document Object Model
Imperative API
Document-centric
Weird data types
<Company name=Microsoft>
<Founders>
<Person>Bill Gates</Person>
</Founders>
</Company>
Document Object Model
XmlDocument doc = new XmlDocument();
XmlElement company = [Link]("Company");
[Link](company);
XmlAttribute name = [Link]("name");
[Link] = "Microsoft";
[Link](name);
XmlElement founders = [Link]("Founders");
[Link](founders);
XmlElement person = [Link]("Person");
[Link](person);
XmlText bill = [Link]("Bill Gates");
[Link](bill);
LINQ to XML
Functional construction
Element-centric (context free)
CLR data types (collection friendly)
LINQ to XML
Functional construction
Element-centric (context free)
CLR data types (collection friendly)
XElement company =
new XElement("Company",
new XAttribute("name", "Microsoft"),
new XElement("Founders",
new XElement("Person", "Bill Gates")
)
);
XML with queries
XML with queries
string[] names = { Anders, Erik, Amanda };
XML with queries
string[] names = { Anders, Erik, Amanda };
from n in names
where [Link](A)
select new XElement(Person, n)
XML with queries
string[] names = { Anders, Erik, Amanda };
XElement employees =
new XElement(Employees,
from n in names
where [Link](A)
select new XElement(Person, n)
);
XML with queries
string[] names = { Anders, Erik, Amanda };
XElement employees =
new XElement(Employees,
from n in names
where [Link](A)
select new XElement(Person, n)
);
[Link](employees);
XML with queries
string[] names = { Anders, Erik, Amanda };
XElement employees =
new XElement(Employees,
from n in names
where [Link](A)
select new XElement(Person, n)
);
[Link](employees);
[Link](company);
XML on the Console
<Company name=Microsoft>
<Founders>
<Person>Bill Gates</Person>
</Founders>
<Employees>
<Person>Anders</Person>
<Person>Amanda</Person>
</Employees>
</Company>
Querying XML
IEnumerable<string> persons =
from p in [Link](Person)
select [Link];
Querying XML
IEnumerable<string> persons =
from p in [Link](Person)
select [Link];
Bill Gates
Anders
Amanda
LINQ to SQL
Querying a SQL backend
Use LINQ to query a relational database
Strongly typed queries
Remote the query to the DBMS
C# must remain API/DB independent
LINQ to SQL
Simple Object Relational Mapper
Microsoft SQL Server
Comes with tool to make classes out of
tables in an existing database
Certainly not the best ORM out there
More advanced stuff: LINQ to Entities
LINQ to SQL example
LINQ to SQL example
LINQ to SQL example
LINQ to SQL example
[DatabaseAttribute(Name="Northwind")]
public partial class NorthwindDataContext :
[Link]
{
public NorthwindDataContext() :
base("Data Source=.;Initial Catalog=Northwind;"
+ "Integrated Security=True")
{
}
public Table<Customer> Customers
{
get { return [Link]<Customer>(); }
}
}
LINQ to SQL example
[Table(Name="[Link]")]
public partial class Customer :
INotifyPropertyChanging, INotifyPropertyChanged
{
private string _CustomerID;
[Column(Storage="_CustomerID",
DbType="NChar(5) NOT NULL",
CanBeNull=false, IsPrimaryKey=true)]
public string CustomerID
{
get { return this._CustomerID; }
set { /* Setter code removed */ }
}
/* More code be here */
}
LINQ to SQL example
LINQ to SQL example
var db = new NorthwindDataContext();
var q = from c in [Link]
where [Link] == London
select c;
LINQ to SQL example
var db = new NorthwindDataContext();
var q = from c in [Link]
where [Link] == London
select c;
foreach (var c in q)
[Link]([Link] +
+ [Link]);
LINQ to SQL example
var db = new NorthwindDataContext();
var q = from c in [Link]
where [Link] == London
select c;
foreach (var c in q)
[Link]([Link] +
+ [Link]);
AROUT Thomas Hardy
BSBEV Victoria Ashworth
CONSH Elizabeth Brown
EASTC Ann Devon
NORTS Simon Crowther
SEVES Hari Kumar
LINQ to SQL example
var q = [Link]<Customer>(
c => [Link] == London);
Lambdas again
Lambdas again
Func<int, int> f = x => (x + 1) * 2;
int nr = f(20);
[Link](nr); // Prints: 42
Lambdas again
Expression<Func<int, int>> e = x => (x + 1) * 2;
Lambdas again
Expression<Func<int, int>> e = x => (x + 1) * 2;
string str = [Link] + + [Link];
[Link](str); // Prints: Lambda 1
Lambdas again
Expression<Func<int, int>> e = x => (x + 1) * 2;
string str = [Link] + + [Link];
[Link](str); // Prints: Lambda 1
Func<int, int> f = [Link]();
[Link](f(20)); // Prints: 42
Lambdas again
Expression<Func<int, int>> e = x => (x + 1) * 2;
Lambdas again
Expression<Func<int, int>> e = x => (x + 1) * 2;
ParameterExpression x =
[Link](typeof(int), "x");
Expression one = [Link](1, typeof(int));
Expression two = [Link](2, typeof(int));
Expression body =
[Link]([Link](x, one), two);
Expression<Func<int, int>> e =
[Link]<Func<int, int>>(body, x);
LINQ to SQL example
var q = [Link]<Customer>(
c => [Link] == London);
LINQ to SQL example
var q = [Link]<Customer>(
c => [Link] == London);
ParameterExpression c =
[Link](typeof(Customer), "c");
IQueryable<Customer> q = [Link]
.Where<Customer>([Link]<Func<Customer, bool>>(
[Link](
[Link](c,
(MethodInfo) methodof(Customer.get_City)),
[Link]("London", typeof(string)), false,
(MethodInfo) methodof(string.op_Equality)), c));
LINQ to SQL example
var q = [Link]<Customer>(
c => [Link] == London);
SELECT C.*
FROM Customers AS C
WHERE [Link] = London
Many more operations
int x = [Link]<Customer>(
c => [Link] == London).Count();
SELECT COUNT(C.*) AS value
FROM Customers AS C
WHERE [Link] = London
Many more operations
int x = [Link]<Customer>(
c => [Link] == London).Take(4);
SELECT TOP (4) C.*
FROM Customers AS C
WHERE [Link] = London
Many more operations
Restriction Where
Projection Select, SelectMany
Partitioning Take, Skip, TakeWhile, SkipWhile
Join Join, GroupJoin
Concatinatin Concat
Ordering OrderBy, ThenBy, Reverse
Grouping GroupBy
Set Distinct, Union, Intersect, Except
Conversion ToArray, ToList, ToDictionary, OfType, Cast
Elemement First, FirstOrDefault, Last, LastOrDefault
Generation Range, Repeat, Empty
Quantifiers Any, All, Contains
Aggregate Count, Sum, Min, Max, Average, Aggregate
Assignment
Assignment
olut i o n
S
Assignment
olut i o n
S
new XElement("rss",
new XAttribute("version", "2.0"),
new XElement("channel",
new XElement("title", "Top Processes"),
from p in
(from p in [Link]()
orderby [Link] descending
select p).Take(5)
join pd in [Link]
on [Link] equals [Link] into descrs
from d in [Link]()
select new XElement("item",
new XElement("title", [Link]),
d != null ? new XElement("description", [Link]) : null)
)
);
Assignment
olut i o n
S
<rss version="2.0">
<channel>
<title>Top Processes</title>
<item>
<title>sqlservr</title>
<description>SQL Server</description>
</item>
<item>
<title>sqlservr</title>
<description>SQL Server</description>
</item>
<item>
<title>devenv</title>
<description>Visual Studio</description>
</item>
<item>
<title>ssmsee</title>
</item>
<item>
<title>Reflector</title>
</item>
</channel>
</rss>
Other providers
DbLinq (MySQL, PostgreSQL, Oracle)
LINQ to Google
LINQ to Entities
Parallel LINQ
DryadLINQ (Distributed execution engine)
Concluding...
All LINQ is:
Query comprehensions
Libraries
Expression trees
Many more providers to come...
Questions?
Assignment in VB syntax
Dim result = _
<rss version="2.0">
<channel>Top Processes</channel>
<%= From p In [Link]() _
Order By [Link] Descending _
Take 5 _
Group Join pd In [Link] _
On [Link] Equals [Link] _
Into descrs = Group _
From d In [Link] _
Select <item>
<title><%= [Link] %></title>
<%= If(d IsNot Nothing, _
<description><%= [Link] %></description>, _
Nothing) %>
</item> %>
</rss>
LINQ in Java
// Setup a JPA entity manager...
SessionFactory sessionFactory =
new Configuration().configure().buildSessionFactory();
EntityManagerFactory entityManagerFactory =
new EntityManagerFactoryImpl(sessionFactory,
PersistenceUnitTransactionType.RESOURCE_LOCAL, true);
QueryableEntityManager entityManager =
new QueryableEntityManager([Link]());
// Select all customers in the Washington region
Iterable<Customer> waCustomers =
from("c").in([Link]([Link])).
where(eq("[Link]()", "WA")).
select("c");
Monadic parser
combinators using C#
public abstract class MiniMLParsers<TInput> : CharParsers<TInput>{
public MiniMLParsers() {
Whitespace = Rep(Char(' ').OR(Char('\t').OR(Char('\n')).OR(Char('\r'))));
WsChr = chr => [Link](Char(chr));
Id = from w in Whitespace
from c in Char([Link])
from cs in Rep(Char([Link]))
select [Link]([Link](),(acc,ch) => acc+ch);
Ident = from s in Id where s != "let" && s != "in" select s;
LetId = from s in Id where s == "let" select s;
InId = from s in Id where s == "in" select s;
Term1 = (from x in Ident
select (Term)new VarTerm(x))
.OR(
(from u1 in WsChr('(')
from t in Term
from u2 in WsChr(')')
select t));
Term = (from u1 in WsChr('\\')
from x in Ident
from u2 in WsChr('.')
from t in Term
from cs in Rep(Char([Link]))
select [Link]([Link](),(acc,ch) => acc+ch);
Monadic parser
Ident = from s in Id where s != "let" && s != "in" select s;
LetId = from s in Id where s == "let" select s;
InId = from s in Id where s == "in" select s;
combinators using C#
Term1 = (from x in Ident
select (Term)new VarTerm(x))
.OR(
(from u1 in WsChr('(')
from t in Term
from u2 in WsChr(')')
select t));
Term = (from u1 in WsChr('\\')
from x in Ident
from u2 in WsChr('.')
from t in Term
select (Term)new LambdaTerm(x,t))
.OR(
(from letid in LetId
from x in Ident
from u1 in WsChr('=')
from t in Term
from inid in InId
from c in Term
select (Term)new LetTerm(x,t,c)))
.OR(
(from t in Term1
from ts in Rep(Term1)
select (Term)new AppTerm(t,ts)));
All = from t in Term from u in WsChr(';') select t;
}