Expression to String respresentation

Nov 8, 2013 at 5:11 AM
Hi,

I am using Dynamic Linq with EF behind my service layer and it is great.

However, I would like to write an IQueryable expression on the client and pass the string representation across the wire and then use Dynamic Linq with EF.

Does anyone have an example of how to convert a expression to the string respresentation?

For example

Where(r => r.Users.Any(u => u.UserName == "test")

to something like

"r => r.Users.Any(u => u.UserName == "test""

Thanks heaps.
Coordinator
Nov 8, 2013 at 8:03 PM
Edited Nov 8, 2013 at 8:15 PM
You will need to use System.Linq.Expression and you will either need access to the object that r (in your example represents) or an analog to it on the client side. The type of the object doesn't have to be the same but the Properties must match (it doesn't matter what type you write the query against since it's being abstracted to a string, but it will matter when you materialize the string to a query that server-side objects support the same properties).

Example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        public class User
        {
            public string UserName
            {
                get;
                set;
            }
        }
        static void Main(string[] args)
        {
            //"r => r.Users.Any(u => u.UserName == "test"" 
            var query = CreateQuery<User>("Users");
            Console.WriteLine(query);
            Console.ReadLine();


        }

        internal static Expression CreateQuery<T>(string name)
        {
            if (name == typeof(T).Name) throw new NotSupportedException("Entity name and type name must be different");
            var param1 = Expression.Parameter(typeof(IQueryable<T>), name);
            var param2 = Expression.Parameter(typeof(T), typeof(T).Name);

           
            ConstantExpression category = Expression.Constant(String.Format("{0}", "test"), typeof(string));
            Expression left = Expression.PropertyOrField(param2, "UserName");
            Expression e1 = Expression.Call(left, left.Type.GetMethod("Equals", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public, null, new[]{ typeof(string) }, null), category);

            e1 = Expression.Call(
               typeof(Queryable),
               "Where",
               new Type[] { typeof(T) },
               param1,
              Expression.Lambda<Func<T, bool>>(e1, new ParameterExpression[] { param2 }));


            return e1;

        }
    }
}
Nov 10, 2013 at 7:34 PM
hello! approximately the same question and I have!
is there a simple way to put the expression in a string?
for example I do queries like
var query = myList.Where (w => w.Count> 5). AsIQueryable().Expression;
and then I do something like query.ToLinqString ()
and getting a string "myList.Where (w => w.Count> 5)" I can already upload to the server and run dynamic?.
Coordinator
Nov 11, 2013 at 4:51 AM
It doesn't really matter how the string is generated as long as it is correctly formatted (it is only a string after all) there is no evidence of its genesis by the time it reaches the server. For Patrick your approach would work if we assume he knew all the potential client-side queries a priori. If however he has to generate the queries dynamically in response to user input this approach would not work. Even the hard coding of the value 5 in your example which would be compiled into the assembly or executable could prove problematic unless we assume you will always want a value of 5, you code for every possible count, or start hacking around in the expression after it's generated in which case you could only hope to modify the constant. So it really depends on the situation and you have to evaluate the approach against the desired functionality.
Nov 11, 2013 at 4:56 AM
Hi alekseevkm,

I've started creating a custom linq provider using re-linq to produce a string representation of the query (format is compliant for DynamicLinq). I then pass this output across the wire where I use DynamicLinq to generate a Linq expression.

Obviously this may not handle 100% of scenarios but it is pretty good.

What do you think?
Nov 11, 2013 at 5:34 AM
Hi TAPatrickNolan,
I am doing at the moment about the same.
I do not have enough funds WCF Data Service to work with the collections through webapi. Do not know if it would be a good idea, but for my project I need it :)
Coordinator
Nov 11, 2013 at 6:26 AM
Edited Nov 11, 2013 at 6:39 AM
alekseevkm...I just looked at your project on CodePlex and if you are trying to do what I think you are you may want to use oData. Take a look [http://stackoverflow.com/questions/9953180/asp-net-webapi-iqueryable-support-with-mongodb-official-c-sharp-driver]
[http://www.strathweb.com/2012/08/supporting-odata-inlinecount-with-the-new-web-api-odata-preview-package/]. Hope this helps.
Nov 11, 2013 at 7:04 AM
ekeratbellsouth,
Yes, I know about this driver, but I have a task which I can not open mongodb access from outside. Besides, I need some caching. and in my oData not support grouping.
Thank you for your answers!