Oops, we did it again
A new update to LINQ preview is available at MSDN site.
What's the coolest new feature? IMHO, its IQueryable<T>.
DLINQ's query mechanism has been generalized and available for all to use as part of System.Query. It implements the Standard Query Operators for you using expression nodes to represent the query. Your queries can now be truly polymorphic, written over a common abstraction and translated into the target environment only when you need it to.
public int CustomersInLondon(IQueryable<Customer> customers) {
int count = (from c in customers
where c.City == "London"
select c).Count();
return count;
}
Now you can define a function like this and it can operate on either an in memory collection or a remote DLINQ collection (or you own IQueryable for that matter.) The query is then either run entirely locally or remotely depending on the target.
If its a DLINQ query a count query is sent to the database.
SELECT COUNT(*) AS [value]
FROM [Customers] AS [t0]
WHERE [t0].[City] = @p0
If its a normal CLR collection, the query is executed locally, using the System.Query.Sequence classes definitions of the standard query operators. All you need to do is turn your IEnumerable<Customer> into IQueryable<Customer>. This is accomplished easily with a built-in ToQueryable() method.
List<Customer> customers = ...;
CustomersInLondon(customers.ToQueryable());
Wow! That was easy. But, how is this done? How can you possible turn my List<T> into some queryable thingamabob?
Good question. Glad you asked.
Check out this little gem:
Expression<Func<Customer,bool>> predicate = c => c.City == "London";
Func<Customer,bool> d = predicate.Compile();
Now you can compile lambda expressions directly into IL at runtime!
ToQueryable() wraps your IEnumerable<T> in IQueryable<T> clothing, uses the Queryable infrastructure to let you build up your own expression tree queries, and then when you enumerate it, the expression is rebound to refer to your IEnumerable<T> directly, the operators rebound to refer to System.Query.Sequence, and the resulting code is compiled using the built-in expression compiler. That code is then invoked producing your results.
Amazing, but true.
But wait, there is more! Yes, it is true, not only can you slice, but you can also dice!
That's not the end of IQueryable<T>'s little bag of tricks. What else could there be? How about dynamic queries, ones you can build up at runtime? Yes? No? Say it isn't so!
It's true. IQueryable<T> is fully dynamic. Sort of. Each IQueryable<T> has a method CreateQuery<S>() that creates a new IQueryable<S> (of the same concrete type) with a single Expression tree argument. That is, if I have an expression tree representing the code that defines a query, I can make an IQueryable<S> out of an old IQueryable<T>.
That's great you say, but you probably don't statically know what the 'T' and 'S' are in your program if you are building dynamic queries at runtime. True, true, we've thought of that too. You see, IQueryable<T> has a smaller cousin, IQueryable, just like IEnumerable<T> has its little friend IEnumerable. IQueryable is non-generic, but its ever so much a query as IQueryable<T>. In fact, it has its own CreateQuery() method that builds a new IQueryable so you can do all this query building without all that static info getting in your way.
So how do you build the expression trees that make up a query. Check out the System.Query.QueryExpression class. It is a collection of static methods that correspond to the standard query operator pattern, but are more loosely typed, taking arguments that are Expression's instead of Expression<T>'s. These methods do all the work necessary to build up the call nodes that represent calls to the more fully typed IQueryable<T> query operator methods.
Here's how you can dynamic build up the query in the prior example.
IQueryable q = ...;
ParameterExpression p = Expression.Parameter(typeof(Customer), "c");
Expression body = Expression.EQ(
Expression.Property(p, typeof(Customer).GetProperty("City")),
Expression.Constant("London")
);
LambdaExpression predicate = QueryExpression.Lambda(body, p);
Expression where = QueryExpression.Where(q.Expression, predicate);
q = q.CreateQuery(where);
You can then call GetEnumerator() on 'q' to execute the query.
Too hard you say? Do I have to write all that code? What if I just want my users to type in a little filter expression. Do I have to turn that into all those nodes?
Ah, well, we've thought of that too. Try this out.
IQueryable q = ...;
ParameterExpression p = Expression.Parameter(typeof(Customer), "c");
LambdaExpression predicate =
QueryExpression.Lambda("c.City = 'London'", p);
Expression where = QueryExpression.Where(q.Expression, predicate);
q = q.CreateQuery(where);
Or if you don't want them to have to type silly dot's, just don't give the parameter a name.
IQueryable q = ...;
ParameterExpression p = Expression.Parameter(typeof(Customer), "");
LambdaExpression predicate =
QueryExpression.Lambda("City = 'London'", p);
Expression where = QueryExpression.Where(q.Expression, predicate);
q = q.CreateQuery(where);
Viola! Instant filter. Instant dynamic query. Run it here. Run it there. Why, you can run it everywhere.
But that's enough from me. Why are you wasting time reading this when you could be downloading the preview and trying it out for yourself?
Matt
Comments
Anonymous
May 10, 2006
Matt,
this stuff is so cool. linq rocks...
WM_THX
thomas woelferAnonymous
May 10, 2006
OMG! This is so cool. I don't know what it is, but it is so cool.Anonymous
May 10, 2006
Show me how that last one can be parameterized to avoid injection issues...Anonymous
May 10, 2006
You wouldn't use that text based filter if you were assembling user input with other pieces, you'd use the node construction pattern. The text based filter would only be used if the entire predicate is supplied by the user. The user cannot cause injection because this expression is parsed, turned into expression nodes that must statically check as a correct predicate. DLINQ automatically converts the user supplied literal into an ADO.Net parameter, so there is no injection on that end either.Anonymous
May 11, 2006
I mentioned this in my last blog entry, but thought I should make it more discoverable. We've released...Anonymous
May 11, 2006
I mentioned this in my last blog entry, but thought I should make it more discoverable. We've released...Anonymous
May 11, 2006
A new LINQ CTP is available. Looking for a reason to install it? See&nbsp;this.Anonymous
May 11, 2006
The comment has been removedAnonymous
May 11, 2006
It would seem that you don't need IEnumerable<T> operators at all anymore. However, you still need them as actual methods to invoke when the IQueryable<T> is executed locally, and its has additional overhead due to the expression tree representation and the runtime compilation.Anonymous
May 11, 2006
There's an update to the LINQ extensions for the .NET framework available on MSDN. Check it out on...Anonymous
May 12, 2006
See (scroll down to the bottom for better samples)
http://www.entityspaces.net/portal/Documentation/QueryAPISamples/tabid/80/Default.aspx
Anyway, LINQ looks very cool Matt, what level are you involved with it?Anonymous
May 12, 2006
AggregateTestCollection aggTestColl = new AggregateTestCollection();
aggTestColl.Query.es.CountAll = true;
aggTestColl.Query
.Select (aggTestColl.Query.IsActive,
aggTestColl.Query.DepartmentID)
.Where (aggTestColl.Query.IsActive.Equal(true))
.GroupBy(aggTestColl.Query.IsActive,
aggTestColl.Query.DepartmentID)
.OrderBy(aggTestColl.Query.DepartmentID.Ascending, aggTestColl.Query.IsActive.Ascending);
aggTestColl.Query.es.WithRollup = true;
aggTestColl.Query.Load();
Yields
==============
SELECT [IsActive],[DepartmentID] ,COUNT(*) AS 'Count' FROM [AggregateTest]
WHERE ([IsActive] = @IsActive1 )
GROUP BY [IsActive],[DepartmentID] WITH ROLLUP
ORDER BY [DepartmentID] ASC,[IsActive] ASC
Same binary code runs on all databases.Anonymous
May 12, 2006
Mike, you could certainly add LINQ to your product. It would be relatively simple to translate IQueryable<T> expression trees into your query API, so it would simply bolt on top of what you have now.
By implementing IQueryable<AggregateTest> on your AggregateTestCollection class your users could write LINQ queries.Anonymous
May 12, 2006
That's exactly what we were thinking. We provide a whole other superset of functionality but thought exactly as you suggested, implement the IQueryable<> syntax. We're releasing 1.4 this weekend which adds MySQL and some other cools stuff. Then 1.5 adds full hierarchical support. Of course we generate it all from your db schema. What's cool is that our NUnit test suite runs the exact same binary code against Oracle, Access, Microosft SQL, and MySQL the only difference being a connection string (of course, you have to use a schema that works in all databases but it's very forgiving). Anyway, we're thinking along the same lines ...Anonymous
May 12, 2006
Добавлены новые возможности: Поддержка запросов времени выполнения, соединений тAnonymous
May 12, 2006
One of the biggest Linq improvements from the last CTP is IQueryable&lt;T&gt; which allows polymorphic...Anonymous
May 14, 2006
Qualche mese fa scrivevo qualche commento relativamente al ruolo di LINQ. Il recente rilascio di una...Anonymous
May 17, 2006
PingBack from http://mdavey.wordpress.com/2006/05/11/linq-may-ctp/Anonymous
May 21, 2006
After false steps of ObjectSpaces and non-existent O/R mapping tools from Microsoft, the LINQ family...Anonymous
May 21, 2006
After false steps of ObjectSpaces and non-existent O/R mapping tools from Microsoft, the LINQ family...Anonymous
May 22, 2006
I do a good amount of work in the multidimentional (MDX) query space. Will LINQ be extended for that paradigm also?Anonymous
May 31, 2006
PingBack from <a href="http://blog.genom-e.com/default,date,2006-05-31.aspx">http://blog.genom-e.com/default,date,2006-05-31.aspx</a>Anonymous
June 02, 2006
We are wellocme to it's configuration.Anonymous
June 04, 2006
This is soo cool.
We are currently implementing Linq support for our opensource mapper (NPersist)
http://blogs.wdevs.com/phirephly/archive/2006/06/05/13420.aspx#13422
it works lovely..
kudos to the Linq team :-)Anonymous
June 17, 2006
The documents on ADO.NET vNext that were previously pulled from MSDN have been republished by Microsoft.I...Anonymous
October 30, 2006
This is the first in a series of posts on C# and LINQ. These posts will describe a natural, easy to understandAnonymous
November 22, 2006
By Matt Duffin. So, you’re creating an application… no surprise there. As part of that application, youAnonymous
April 03, 2007
The comment has been removed