Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do a left outer join with Dynamic Linq?

Tags:

I am trying to mimick the left outer join here but using dynamic linq extension methods. What i have:

public static IQueryable SelectMany(this IQueryable source, string selector,      string resultsSelector, params object[] values) {     if (source == null) throw new ArgumentNullException("source");     if (selector == null) throw new ArgumentNullException("selector");      // Parse the lambda      LambdaExpression lambda = DynamicExpression.ParseLambda(         source.ElementType, null, selector, values);      // Fix lambda by recreating to be of correct Func<> type in case       // the expression parsed to something other than IEnumerable<T>.      // For instance, a expression evaluating to List<T> would result       // in a lambda of type Func<T, List<T>> when we need one of type      // an Func<T, IEnumerable<T> in order to call SelectMany().      Type inputType = source.Expression.Type.GetGenericArguments()[0];     Type resultType = lambda.Body.Type.GetGenericArguments()[0];     Type enumerableType = typeof(IEnumerable<>).MakeGenericType(resultType);     Type delegateType = typeof(Func<,>).MakeGenericType(inputType,          enumerableType);     lambda = Expression.Lambda(delegateType, lambda.Body, lambda.Parameters);      ParameterExpression[] parameters = new ParameterExpression[] {          Expression.Parameter(source.ElementType, "outer"),          Expression.Parameter(resultType, "inner")      };      LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(         parameters, null, resultsSelector, values);      // Create the new query      return source.Provider.CreateQuery(Expression.Call(typeof(Queryable),          "SelectMany", new Type[] {              source.ElementType,              resultType,              resultsSelectorLambda.Body.Type          }, source.Expression, Expression.Quote(lambda),          Expression.Quote(resultsSelectorLambda)));             } 

and:

public static IQueryable GroupJoin(this IQueryable outer, IEnumerable inner,     string outerKeySelector, string innerKeySelector, string resultSelector,      params object[] values) {     Type innerElementType = inner.AsQueryable().ElementType;      var outerParameter = Expression.Parameter(outer.ElementType, "outer");     var innerParameter = Expression.Parameter(innerElementType, "inner");     var groupParameter = Expression.Parameter(typeof(IEnumerable<>)         .MakeGenericType(innerElementType), "group");      var outerLambda = DynamicExpression.ParseLambda(new[] { outerParameter },         null, outerKeySelector, values);     var innerLambda = DynamicExpression.ParseLambda(new[] { innerParameter },         outerLambda.Body.Type, innerKeySelector, values);     var resultLambda = DynamicExpression.ParseLambda(new[] {          outerParameter, groupParameter }, null, resultSelector, values);      return outer.Provider.CreateQuery(Expression.Call(typeof(Queryable),          "GroupJoin", new[] { outer.ElementType, innerElementType,          outerLambda.Body.Type, resultLambda.Body.Type },         outer.Expression, Expression.Constant(inner),         Expression.Quote(outerLambda), Expression.Quote(innerLambda),         Expression.Quote(resultLambda))); } 

However where I fall down is with the DefaultIfEmpty within the SelectMany

like image 307
jaywayco Avatar asked Sep 09 '11 16:09

jaywayco


People also ask

How left outer join implement in LINQ?

A left outer join is a join in which each element of the first collection is returned, regardless of whether it has any correlated elements in the second collection. You can use LINQ to perform a left outer join by calling the DefaultIfEmpty method on the results of a group join.

Is LINQ join inner or outer?

One commonly used feature of Language-Integrated Query (LINQ) is the facility to combine two sequences of related data using joins. The standard join operation provides an inner join but with a minor modification can be changed to give a left outer join.

What is Dynamic LINQ?

The Dynamic LINQ library exposes a set of extension methods on IQueryable corresponding to the standard LINQ methods at Queryable, and which accept strings in a special syntax instead of expression trees.


1 Answers

Add void DefaultIfEmpty(); to interface IEnumerableSignatures

Then use

public static object DefaultIfEmpty(this IQueryable source) {     if (source == null) throw new ArgumentNullException("source");         return source.Provider.Execute(     Expression.Call(         typeof(Queryable), "DefaultIfEmpty",         new Type[] { source.ElementType },         source.Expression)); } 

Then you have a call like

var qry = Foo.GroupJoin(Bar, "outer.Id", "inner.Id", "new(outer.Id as Foo, group as Bars)").SelectMany("Bars.DefaultIfEmpty()", "new(outer.Foo as Foo, inner as Bar)"); 
like image 186
Josh Avatar answered Sep 20 '22 13:09

Josh