none
Dynamic expression tree building - incorporate parent child relation in one expression with paramters, constants and lambda's

    Question

  • I'm trying to design a functionality that requires the use of dynamic expression trees.
    For this purpose i use the LinqKit (AsExpandable(), Expand, PredicateBuilder...) extension a lot.

    I've run into a problem though.

    Here is some code to set the context of my question:

    using System;
    
    using System.Linq;
    
    using System.Linq.Expressions;
    
    
    
    namespace Company.DynamicLinq
    
    {
    
     public interface IDynamicQueryAdapter
    
     {
    
      IQueryable<T> GetQueryable<T>() where T : class;
    
      Expression<Func<TParentEntity, TChildEntity, bool>> GetJoinExpression<TParentEntity, TChildEntity>();
    
     }
    
    }
    
    

    An IDynamicQueryAdapter instance is responsible for:

    • Resolving requests for an IQueryable<>
      In my case this is achieved by returning the result of a linq 2 SQL Datacontext.GetTable<>() invocation.
    • Returning an Expression which defines a join.
      In my case this is achieved by reflection: AssociationAttribute (code posted in an other thread, if you are interested to see).
    public sealed class SubQuery<TChildEntity> : SubQuery
    
      where TChildEntity : class
    
     {
    
      public override IQueryable<TParentEntity> GetParentResults<TParentEntity>(IDynamicQueryAdapter ctx)
    
      {
    
       Expression<Func<TParentEntity, TChildEntity, bool>> joinExpr = ctx.GetJoinExpression<TParentEntity, TChildEntity>();
    
    
    
       Expression<Func<TChildEntity, bool>> childSelectionExpression = GetExpression<TChildEntity>(ctx);
    
    
    
       return (from parentEntity in ctx.GetQueryable<TParentEntity>().AsExpandable()
    
         let childEntities = ctx.GetQueryable<TChildEntity>().Where(p => joinExpr.Invoke(parentEntity, p))
    
         where childEntities.Any(childSelectionExpression)
    
         select parentEntity);
    
      }
    
    
    
    
    
      public override Expression<Func<TParentEntity, bool>> GetParentExpression<TParentEntity>(IDynamicQueryAdapter ctx)
    
      {
    
       Expression<Func<TParentEntity, TChildEntity, bool>> joinExpr = ctx.GetJoinExpression<TParentEntity, TChildEntity> ();
    
       
    
       Expression<Func<TChildEntity, bool>> childSelectionExpression = GetExpression<TChildEntity>(ctx);
    
    
    
       Expression<Func<TParentEntity, bool>> parentSelectionExpression =
    
        (parentEntity) =>
    
        ctx.GetQueryable<TChildEntity>().Where((child) => joinExpr.Invoke(parentEntity, child)).Any(childSelectionExpression);
    
    
    
       return parentSelectionExpression;
    
      }
    
     }
    
    

    It is the class above that troubles me.
    More specifically, the method GetParentExpression<TParentEntity>

    That method needs to return the expression that would (when used) have the same result as the invocation of GetParentResults<TParentEntity>
    I'm currently rewriting the method to achieve this, but i'm stuck were the comments begin.

    public override Expression<Func<TParentEntity, bool>> GetParentExpression
    
       <TParentEntity>(IDynamicQueryAdapter ctx)
    
      {
    
       Expression<Func<TParentEntity, TChildEntity, bool>> joinExpr =
    
        ctx.GetJoinExpression<TParentEntity, TChildEntity> ();
    
       Expression<Func<TChildEntity, bool>> childSelectionExpression = GetExpression<TChildEntity>(ctx);
    
    
    
    
    
       ParameterExpression parentParameter = Expression.Parameter(typeof (TParentEntity), "parentEntity");
    
       ConstantExpression dynQryAdapter = Expression.Constant(ctx);
    
    
    
       MethodInfo queryableFactoryMethod = typeof (IDynamicQueryAdapter).GetMethod("GetQueryable");
    
       queryableFactoryMethod = queryableFactoryMethod.MakeGenericMethod(typeof (TChildEntity));
    
    
    
       MethodCallExpression getChilderenQueryable = Expression.Call (dynQryAdapter, queryableFactoryMethod);
    
       
    
       // express the where relation (invoke joinExpr with correct paramters
    
    
    
       // express the Any clause
    
    
    
       // build the entire lambda and return
    
       
    
    
    
       Expression<Func<TParentEntity, bool>> parentSelectionExpression =
    
        (parentEntity) =>
    
        ctx.GetQueryable<TChildEntity>().Where((child) => joinExpr.Invoke(parentEntity, child)).Any(
    
         childSelectionExpression);
    
    
    
    
    
       return parentSelectionExpression;
    
      }
    
    

    Is anyone able to help me a bit further on my way?

    Thx in advance,

    Simon


     

     

    • Edited by c0nundrum Wednesday, February 02, 2011 10:56 AM
    Monday, January 31, 2011 3:51 PM

All replies

  • Hello Simon,

     

    Nice to see you again and thanks for your post.

    According to your description, I guess maybe the key of your issue is the Invokes. I found this sample in the StackOverFlow:

    public Expression<Func<TEntity, bool>> And(Expression<Func<TEntity, bool>> ex1,  
                                               
    Expression<Func<TEntity, bool>> ex2) 
    { 
     
    var x = Expression.Parameter(typeof(TEntity)); 
     
    return Expression.Lambda<Func<TEntity,bool>>( 
       
    Expression.And( 
         
    Expression.Invoke(ex1, x), 
         
    Expression.Invoke(ex2, x)), x);  
    } 

    And note that won't work with Entity Framework unless you compact the Invokes. Google InvocationExpander for an implementation.

    Here is the InvocationExpander.cs http://code.google.com/p/simpledotnet/source/browse/trunk/src/Simple/Expressions/InvocationExpander.cs?r=1076

     

    So I hope this can help you.

     

    have a nice day,


    Jackie Sun [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, February 02, 2011 5:22 AM

  • Thank you for your response, but i'm afraid, for once, it isn't helpful :-)
    I've reread my own post and i must say i bear a responsability for that, i wasn't very clear.

    I've written some code which i use to allow my application users to query their database.

    It all revolves around the ability to build expressions of the following type:

    <Func<TParentEntity, bool>>

    Futhermore, they can add criteria for entities which are related (parent / child) to the TParentEntity.
    They are enabled to build multiple expressions and group/combine them with AND / OR - and negate them (NOT).

    As i've designed it now, all the expressions user defined expressions of type Expression<Func<TParentEntity,bool>> are combined first.

    Then i do something as the following:

    IQueryable<TParentEntity> baseQueryable = (from parentEntity in parentQueryable where compositeParentExpression.Invoke(parent) select parent);

    After that i start with alle the child expressions (i call those subexpressions) like this:

    baseQueryable = (from parentEntity in baseQueryable.AsExpandable()
    let childeren = childerenQueryable.Where(p=>joinExpression.Invoke(parentEntity, p))  
    where childeren.Any(childSelectionExpression)
     select parentEntity);

    After all the sub expressions are added to the baseQueryable the user is presented with a resultset, resulting from all the criteria (expressions) he defined.

    For numerous reasons, it would be better if i could achieve the same functionallity, not by combining child and parent expressions using the baseQueryable approach, but by combining the expressions.

    The problem there lies in the fact that the parent selection Expression is of type: Expression<Func<TParentEntity, bool>> and the child selection Expression would be Expression<Func<TChildEntity,bool>>.
    To complicate matters further, i need an expression which defines the join, which would be of type Expression<Func<TParentEntity, TChildEntity, bool>>.

    Basically, what i want is an expression tree of type Expression<Func<TParentEntity, bool>>, which incorperates the child selection expression tree (and the join expression). Let's call this expression the utopia expression :-)

    So my utopia expression is the combination of all the expressions (parent selection, child selection, join expression, where and any, basically what i do in the code above, the second time baseQueryable is assigned), built dynamically.

    To achieve this i must build my expression using Expression.<factory method> syntax. And add all needed ParamterExpressions, ConstantExpressions, LambdaExressions....

    But i don't seem to be able to get my head around exactly how i must do this. Maybe because the reasoning above is incorrect and my utopia exression isn't more than utopia :-)
    Or maybe because i haven't slept much and this is my fist Linq project. (not counting dummy linq to object stuff)

    Anyway, i haven't looked at the code since my post an will try again today. Hope i will find it, if i do i will post back.

    If anyone out there has some suggestions, they would really be appreciated :-)

    Jackie Sun, you were correct in saying i needed the functionality you describe, i use linqkit for those purposes.

     

     

    • Edited by c0nundrum Wednesday, February 02, 2011 10:54 AM formatting
    Wednesday, February 02, 2011 9:31 AM
  • Below is wat the debug view of the needed expression looks like. To make it al little bit more readable i added some color coding and such.

    AnonType is declared as following:

      var anonTypeVariable = new
      {
       parentEntity = default (TParentEntity),
    childEntities = default (IQueryable<TChildEntity>) };

    Type AnontType = typeof(anonTypeVarialbe);

     

        .Call System.Linq.Queryable.Where(

            .Call System.Linq.Queryable.Select(

                .Constant<System.Data.Linq.Table`1[TParentEntity]>(Table(Patienten)),

                '(.Lambda #Lambda1<System.Func`2[TParentEntity,AnonTypeVariable]>))

            ,

            '(.Lambda #Lambda2<System.Func`2[AnonTypeVariable,System.Boolean]>))

     

    .Lambda #Lambda1<System.Func`2[TParentEntity,AnonTypeVariable]>(TParentEntity $parentEntity)

    {

        .New AnonTypeVariable(

            $parentEntity,

            .Call System.Linq.Queryable.Where(

                .Call (.Constant<Corilus.DynamicLinq.SubQuery`1+<>c__DisplayClass4`1[TChildEntity,TParentEntity]>(Corilus.DynamicLinq.SubQuery`1+<>c__DisplayClass4`1[TChildEntity,TParentEntity]).ctx).GetQueryable()

                ,

                '(.Lambda #Lambda4<System.Func`2[TChildEntity,System.Boolean]>)))

    }

     

    .Lambda #Lambda2<System.Func`2[AnonTypeVariable,System.Boolean]>(AnonTypeVariable $<>h__TransparentIdentifier3)

    {

        .Call System.Linq.Queryable.Any(

            $<>h__TransparentIdentifier3.childEntities,

            '(.Lambda #Lambda5<System.Func`2[TChildEntity,System.Boolean]>))

    }

     

     

    .Lambda #Lambda4<System.Func`2[TChildEntity,System.Boolean]>(TChildEntity $p) {

        $parentEntity.Autonumber == (System.Guid)$p.Patient

    }

     

    .Lambda #Lambda5<System.Func`2[TChildEntity,System.Boolean]>(TChildEntity $p) {

        ((System.Nullable`1[System.Int32])$p.verwijderd == null || (System.Nullable`1[System.Int32])$p.verwijderd == (System.Nullable`1[System.Int32])48

        && ($p.IsFamilial == (System.Nullable`1[System.Boolean])False || $p.IsFamilial == null) && ($p.IsProblem == (System.Nullable`1[System.Boolean])False

        || $p.IsProblem == null)) && .Call System.Data.Linq.SqlClient.SqlMethods.Like(

            $p.Diagnose1,

            .Constant<Accrimed.QueryBuilder.DiagnosisExpressionBuilder+<>c__DisplayClass2+<>c__DisplayClass4>(Accrimed.QueryBuilder.DiagnosisExpressionBuilder+<>c__DisplayClass2+<>c__DisplayClass4).s)

    }

    • Edited by c0nundrum Thursday, February 03, 2011 9:51 AM removed Lambda3 (redundant)
    Thursday, February 03, 2011 9:10 AM
  • Hi,

    I love dynamically building Expression Tree.  :)   However, after reading your posts, I still cannot catch the main point of your request. 

    For dynamically building Expression Tree and LINQ query, I believe the source codes of the Dynamic LINQ Library is the best learning material.  http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.

    Have a nice weekend!

    Thanks


    Michael Sun [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, February 04, 2011 7:47 AM
  • Hi,

     

    If I have someting like this
    var  filteredCollection =   from item in items 

                                         select new {

                                           UniqueId = item.UniqueId,

                                           HasChildren = (from item2 in items where item2.ParentId == item.UniqueId select item2).Any()

                                        }

     

    How can I build:  HasChildren = (from item2 in items where item2.ParentId == item.UniqueId select item2).Any()

    as Expression Tree

    Tuesday, November 22, 2011 11:34 PM