none
Crossing two (or More) collections With Expression Trees RRS feed

  • Question

  • The following search will use the first of four SelectMany overloads.  ()

    Example 1

    var v = from pa in dataContext.Person

        from n in pa.PersonNames

        where n.FirstName.StartsWith("M")

       select n;

     

    I have this working.  Now I need to have a more realistic situation whereby the query will cross multiple collections.  For example the below code:

     

    Example 2

    var v = from pa in dataContext.Person

        from n in pa.PersonNames

        from i in pa.PersonIdentifiers

        where n.FirstName.StartsWith("M") || i.Ident.Equals("1001")

        select n;

     

    With this query in Example 2, I believe I need to use a different overload of the SelectMany extension method than I used in Example 1.  The overload wich I think I need is the following:

     

    public static IQueryable<TResult> SelectMany<TSource, TCollection, TResult>(

        this IQueryable<TSource> source,

        Expression<Func<TSource, IEnumerable<TCollection>>> collectionSelector,

        Expression<Func<TSource, TCollection, TResult>> resultSelector

    )

     

    My initial attempt was:

     

    ParameterExpression personExp = Expression.Parameter(typeof(Person), "Person");

     

    var selectManyNameArg = Expression.Lambda<Func<Person, IEnumerable<PersonName>>>(

        Expression.Property(personExp, "PersonNames"), personExp);

    var selectManyIdenArg = Expression.Lambda<Func<Person, IEnumerable<PersonIdentifier>>>(

        Expression.Property(personExp, "PersonIdentifiers"), personExp);

    Expression selectManyCall = Expression.Call(

       typeof(Queryable),

       "SelectMany",

       new Type[] { typeof(Person), typeof(PersonName), typeof(PersonIdentifier)},                

       Expression.Constant(queryableData),

       selectManyNameArg,

       selectManyIdenArg);

     

    But again I keep getting the same exception which is being thrown from the SelectMany extension method. The arguments I have provided do not match up with any of the signatures for the SelectMany overloads.   Documentation on Expression Trees (other than the simple expression1 greater than expression2 samples) is scarce.  At this point I am not even sure what the best way to debug the issue is.  Any help would be appreciated.

     

     

    Friday, January 30, 2009 11:56 AM

All replies

  • Hi,

    I think your approach is not quite right.  One of the things you need to know is that lambda expressions convert to expression trees, which is one of their distinguishing characteristics.  Therefore, any time that you see a LINQ operator signature that takes an Expression tree, it really means that you can pass a lambda matching the Expression's type parameter.  Here's some pseudo code that might show you what I mean:

            var v =        
                dataContext        
                .Person        
                .SelectMany(        
                    pa => pa.PersonNames,        
                    (n, i) => new { n, i });       
                .Where(ni => n.FirstName.StartsWith("M")); 

    As you can see, each parameter is a lambda.  Even though you will probably be able to use the specified SelectMany operator, it still might not produce the results you want.  My gut feeling is that a set of joins might get you to where you need to be faster, rather than SelectMany; Then again, that depends on what you want the output to look like.

    Joe


    Free C# Tutorial @ http://www.csharp-station.com
    Saturday, January 31, 2009 5:13 AM
    Answerer