Question

Say I have the following query how can I get the base Expression Tree?

MyContext.Items.Select(i=>i.Color);

I want to get the expression tree of this so that I can then use the expression tree to dynamically set what property is being selected (So I can choose Color, Size, Weight, Price etc.)

I think I am close with the following but I keep getting errors:

        IQueryable<Item> query = c.Items;


        string SelctField = "Color";
        ParameterExpression pe = Expression.Parameter(typeof(Item), "i");
        Expression SelectProperty = Expression.Property(pe, SelctField);

        MethodCallExpression Select = Expression.Call(
            typeof(Queryable),
            "Select",
            new Type[] {query.ElementType},
            pe,
            Expression.Lambda<Func<Item, string>>(SelectProperty, pe));

        var result =  query.Provider.CreateQuery<string>(Select);

The above results in

No generic method 'Select' on type 'System.Linq.Queryable' is compatible with the
supplied type arguments and arguments. No type arguments should be provided if the 
method is non-generic

so I tried removing that overload and just keep getting different errors.

I do also get this internal expression text in debug mode, but don't understand how to convert it.

    .Call System.Linq.Queryable.Select(
    .Call .Constant<System.Data.Entity.Core.Objects.ObjectQuery`1[Inventory_Ordering_And_Reporting.Item]>(System.Data.Entity.Core.Objects.ObjectQuery`1[Inventory_Ordering_And_Reporting.Item]).MergeAs(.Constant<System.Data.Entity.Core.Objects.MergeOption>(AppendOnly))
    ,
    '(.Lambda #Lambda1<System.Func`2[Inventory_Ordering_And_Reporting.Item,System.Nullable`1[System.String]]>))

    .Lambda      #Lambda1<System.Func`2[Inventory_Ordering_And_Reporting.Item,System.Nullable`1[System.String]]>(Inventory_Ordering_And_Reporting.Item $i)
{
    $i.Color
}
Was it helpful?

Solution

Not entirely sure if this will work with DB provider, but hopefully since it's purely expression based.

public class Item
{
    public string Blah { get; set; }
    public string Foo { get; set; }
}

[TestMethod]
public void Test()
{
    string propertyName = "Blah";
    System.Linq.Expressions.ParameterExpression arg = System.Linq.Expressions.Expression.Parameter(typeof(Item), "x");

    PropertyInfo pi = typeof(Item).GetProperty(propertyName,
    BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    System.Linq.Expressions.Expression expr = System.Linq.Expressions.Expression.Property(arg, pi);
    System.Linq.Expressions.LambdaExpression lambda = System.Linq.Expressions.Expression.Lambda(expr, arg);
    System.Linq.Expressions.Expression<Func<Item, string>> funcExpression = (System.Linq.Expressions.Expression<Func<Item, string>>)lambda;

    List<Item> test = new List<Item> { new Item { Blah = "Test", Foo = "Another" } };
    IQueryable<Item> query = test.AsQueryable();
    var result = query.Select(funcExpression).ToList();
}

OTHER TIPS

You could use reflection:

    public static void DoStuff(string fieldName)
    {
        List<test> ban = new List<test>();
        ban.Add(new test() { number = 40, notNumber = "hi" });
        ban.Add(new test() { number = 30, notNumber = "bye" });


        var result = ban.Select(item => item.GetType().GetField(fieldName).GetValue(item));
        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
    class test
    {
        public int number;
        public string notNumber;
    }

This example is for fields the select should probably check to see if the field exists and if not then look for a property.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top