Code CSS

Showing posts with label Dynamic LINQ. Show all posts
Showing posts with label Dynamic LINQ. Show all posts

Wednesday, March 28, 2012

Converting IQueryable to IQueryable<T> with Dynamic LINQ

In a previous post I talked about using Dynamic LINQ. While extremely powerful, the results of all Dynamic LINQ queries are IQueryable, which loses the benefits of working with a strongly typed IQueryable<T>. Even worse, the elements in an IQueryable result of a Dynamic LINQ query are generated on the fly and derived from DynamicClass included in the sample, so you can't even build a static converter to get query results into your own type. I struggled with this off and on for weeks, because I needed a way to return an IQueryable<T> from a function that used Dynamic LINQ without enumerating the results.

I finally found the solution in a wonderful enhancement of Microsoft's Dynamic LINQ sample. Krzysztof Olczyk has worked some magic to add several handy features to Dynamic.cs, one of which allows the casting of query results back to a known type. So with his version of Dynamic.cs, you can do this:

IQueryable<MyType> Results = MyResults.Select<MyType>("new @out (Prop1, Prop2)");

This is great because it bridges the gap between the performance and flexibility of Dynamic LINQ and the type-safety of standard LINQ, and you get the best of both worlds!

UPDATE: The relevant code for the Select<T> function is below, but I highly recommend you check out the other enhancements he as added as well.

        private static IQueryable Select(Type type, IQueryable source, string selector, object[] values) {
            if (source == null) throw new ArgumentNullException("source");
            if (selector == null) throw new ArgumentNullException("selector");
            LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, type, selector, values);
            return source.Provider.CreateQuery(
                Expression.Call(
                    typeof(Queryable), "Select",
                    new Type[] { source.ElementType, lambda.Body.Type },
                    source.Expression, Expression.Quote(lambda)));
        }
                
                public static IQueryable Select(this IQueryable source, string selector, params object[] values) {
                        return Select(null, source, selector, values);
                }
                
                public static IQueryable<T> Select<T>(this IQueryable source, string selector, params object[] values) {
                        return Select(typeof(T), source, selector, values) as IQueryable<T>;
                }

Thursday, February 16, 2012

GroupBy with Dynamic LINQ

Dynamic LINQ using System.Linq.Dynamic

First of all, when people talk about "Dynamic LINQ" there are any number of things they could be referring to. I want to mention a tidbit about the DynamicQuery sample that is delivered with Visual Studio. In Visual Studio 2010, the sample is in the following directory:

\Program Files (x86)\Microsoft Visual Studio 10.0\Samples\

Somewhere beneath that directory you will find the CSharpSamples.zip file, which contains a LinqSamples\DynamicQuery path with the dynamic querying capability I'm referring to.  I first learned about this from Scott Guthrie's blog.

The DynamicQuery example contains the Dynamic.cs file, which is a set of extension methods and an expression language that allow you to easily manipulate LINQ queries at runtime. This is incredibly powerful but is sparsely documented and introduces a few problems I'll discuss in later posts.

Group By with Dynamic LINQ

I had a really hard time finding examples of how to group results using Dynamic LINQ, so here's a simple example I came up with:

List<Data> datalist = new List<Data>();
datalist.Add(
    new Data() { Num1 = 1, Num2 = 2, Str1 = "A", Str2 = "Red" });
datalist.Add(
    new Data() { Num1 = 2, Num2 = 5, Str1 = "A", Str2 = "Blue" });
datalist.Add(
    new Data() { Num1 = 3, Num2 = 8, Str1 = "A", Str2 = "Red" });
datalist.Add(
    new Data() { Num1 = 4, Num2 = 12, Str1 = "B", Str2 = "Red" });

var test = datalist.AsQueryable()
    .GroupBy("new(Str1,Str2)", "new(Num2,Num1)");
    .Select("new(Key.Str1, Key.Str2, Average(Num2) as SumNum, Max(Num1) as MaxNum)");

foreach (object o in test)
    Console.WriteLine(o.ToString());
In the example, the "Data" class is just a class with three properties, Num1, Num2, Str1, and Str2 to simulate a table of data. I couldn't find documentation on the GroupBy method anywhere, so I hope this helps someone else.