How to convert lambda to Expression Trees format?

Asked

Viewed 253 times

3

How to convert that lambda:

Set.Asqueryable(). Where(profile => profile.CostCenters.Select(Costcentre => Costcentre.Id). Any(Id => Ids.Contains(Id))).Tolist()

Actually I managed to do even the part: profile.CostCenters.Select(Costcentre => Costcentre.Id) and I’m stuck on how to do the .Any(Id => Ids.Contains(Id))

static void Main(string[] args)
{
    var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);

    Ids = AboveLambdaConvertedToExpressionTree(profileExample);

    var result = Set.AsQueryable().Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id))).ToList();

    //Expression<Func<Profile, bool>> lambda = (Profile) => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id));

    var id = Expression.Parameter(typeof(long), "Id");
    var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
    var profile = Expression.Parameter(typeof(Profile), "Profile");
    var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
    var selectCall = Expression.Call(typeof(Enumerable),
                             "Select",
                             new Type[] { typeof(CostCentre), typeof(long) }, 
                             Expression.PropertyOrField(profile, "CostCenters"),
                             selectLambda);                                   
}

For more details follow the full code below:

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

namespace ExpressionTrees
{
    class Program
    {
        static void Main(string[] args)
        {
            var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);

            Ids = AboveLambdaConvertedToExpressionTree(profileExample);

            var result = Set.AsQueryable().Where(profile => profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id))).ToList();
            //How to convert above lambda to expression tree?????
            //NowThatAboveLambdaConvertedToExpressionTree(Set);

            //Expression<Func<Profile, bool>> lambda = (profile) => profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id));
            //Convert that is great too!

            //var result = Set.AsQueryable().Where(lambda).ToList(); 
            //Same result

            //Expected result result.Count == 2
        }
        static IEnumerable<Int64> AboveLambdaConvertedToExpressionTree(Profile profileExample)
        {
            // I show that as example of what i need to do

            //Begin     var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);
            var property = profileExample.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.Name != "Id").First();
            var collection = ((IEnumerable)property.GetValue(profileExample, null)).AsQueryable();
            var collectionType = property.PropertyType.GetGenericArguments()[0];
            var collectionTypeName = collectionType.Name;

            var keyType = typeof(Int64);
            var keyName = "Id";
            //BeginWhere
            var parameter = Expression.Parameter(collectionType, collectionTypeName);

            var profileExampleWhere = Expression.Lambda(
                                                Expression.NotEqual(parameter, Expression.Constant(null)),
                                                parameter);

            var profileExampleWhereCall = Expression.Call(typeof(Enumerable),
                                                                    "Where",
                                                                    new Type[] { collectionType },
                                                                    collection.Expression,
                                                                    profileExampleWhere);
            //EndWhere

            //BeginSelect
            var profileExampleSelect = Expression.Lambda(Expression.PropertyOrField(parameter, keyName),
                                             parameter);

            var profileExampleSelectCall = Expression.Call(typeof(Enumerable),
                                                      "Select",
                                                      new Type[] { collectionType, keyType },
                                                      profileExampleWhereCall,
                                                      profileExampleSelect);



            var Ids = Expression.Lambda(profileExampleSelectCall).Compile().DynamicInvoke();
            //EndSelect
            //End     var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);

            return ((IEnumerable)Ids).Cast<Int64>();
        }
        public partial class Profile
        {
            public virtual Int64 Id { get; set; }

            public virtual ICollection<CostCentre> CostCenters { get; set; }
        }


        public partial class CostCentre
        {
            public virtual Int64 Id { get; set; }
        }
        public static Profile profileExample
        {
            get
            {
                return new Profile()
                {
                    Id = 1,
                    CostCenters = new List<CostCentre>() { new CostCentre() { Id = 2 } }
                };
            }
        }

        public static IList<Profile> Set
        {
            get
            {
                return new List<Profile>() { new Profile() { Id = 1, 
                                                            CostCenters = new List<CostCentre>() {  new CostCentre() { Id = 1 }, 
                                                                                                    new CostCentre() { Id = 2 } } 
                                                          },            
                                            new Profile() { Id = 2, 
                                                            CostCenters = new List<CostCentre>() {  new CostCentre() { Id = 2 }, 
                                                                                                    new CostCentre() { Id = 3 } } 
                                            },
                                            new Profile() { Id = 3, 
                                                            CostCenters = new List<CostCentre>() {  new CostCentre() { Id = 3 } } 
                                            } };
            }
        }
    }
}
  • What you have already tried and failed. If you have the expression tree just go through it with the Bugger or the Linqpad.

  • Does the answer have to be necessarily using expression trees? Or can I simply simplify your initial expression?

  • The goal is to generate a dynamic lambda Expression... so I think the only way is with expression trees... I tried Linq.Dynamic but there can’t stand everything I need.

  • @It wasn’t easier to use Intersect instead of using Select with Any?

  • It would be more error in Entity framework 5.0 do not know if error in 6.0. I can only use 5.0 because of Oracle Provider. :(

1 answer

2

Solved with the help of Microsoft Mads.

class Program
{
    static void Main(string[] args)
    {
        //var Ids = profileExample.CostCenters.Where(CostCentre => CostCentre != null).Select(CostCentre => CostCentre.Id);

        var Ids = AboveLambdaConvertedToExpressionTree(profileExample);

        //var result = Set.AsQueryable().Where(Profile => Profile.CostCenters.Select(CostCentre => CostCentre.Id).Any(Id => Ids.Contains(Id))).ToList();

        var id = Expression.Parameter(typeof(long), "Id");
        var costCentre = Expression.Parameter(typeof(CostCentre), "CostCentre");
        var profile = Expression.Parameter(typeof(Profile), "Profile");
        var selectLambda = Expression.Lambda(Expression.PropertyOrField(costCentre, "Id"), costCentre);
        var selectCall = Expression.Call(typeof(Enumerable),
                                 "Select",
                                 new Type[] { typeof(CostCentre), typeof(long) }, 
                                 Expression.PropertyOrField(profile, "CostCenters"),
                                 selectLambda);                      

        //var id2 = Expression.Parameter(typeof(long), "Id");

        var containsCall = Expression.Call(typeof(Enumerable),
                              "Contains",
                              new Type[] { typeof(long) },
                              Expression.Constant(Ids),
                              id);

        var anyLambda = Expression.Lambda(containsCall, id);

        var anyCall = Expression.Call(typeof(Enumerable),
                     "Any",
                     new Type[] { typeof(long) },
                     selectCall,
                     anyLambda);

        var whereLambda = Expression.Lambda(anyCall, profile);

        var callExpression = Expression.Call(typeof(Queryable),
                                                    "Where",
                                                    new Type[] { typeof(Profile) },
                                                    Set.AsQueryable().Expression,
                                                    whereLambda);


        var result = Expression.Lambda(callExpression).Compile().DynamicInvoke();


    }

Browser other questions tagged

You are not signed in. Login or sign up in order to post.