There was a library of dynamic LINQ extensions methods released as a sample with Visual Studio 2008. I'd like to extend it with a join method. The code below fails with a parameter miss match exception at run time. Where is the problem?
public static IQueryable Join(this IQueryable outer, IEnumerable inner,
string outerSelector, string innerSelector, string resultsSelector,
params object[] values)
{
if (inner == null)
throw new ArgumentNullException("inner");
if (outerSelector == null)
throw new ArgumentNullException("outerSelector");
if (innerSelector == null)
throw new ArgumentNullException("innerSelector");
if (resultsSelector == null)
throw new ArgumentNullException("resultsSelctor");
LambdaExpression outerSelectorLambda =
DynamicExpression.ParseLambda(outer.ElementType, null,
outerSelector, values);
LambdaExpression innerSelectorLambda =
DynamicExpression.ParseLambda(inner.AsQueryable().ElementType,
null, innerSelector, values);
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(outer.ElementType, "outer"),
Expression.Parameter(inner.AsQueryable().ElementType,
"inner")
};
LambdaExpression resultsSelectorLambda =
DynamicExpression.ParseLambda(parameters, null,
resultsSelector, values);
return outer.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Join", new Type[] {
outer.ElementType,
inner.AsQueryable().ElementType,
outerSelectorLambda.Body.Type,
innerSelectorLambda.Body.Type,
resultsSelectorLambda.Body.Type
},
outer.Expression, inner.AsQueryable().Expression,
Expression.Quote(outerSelectorLambda),
Expression.Quote(innerSelectorLambda),
Expression.Quote(resultsSelectorLambda))
);
}
LINQ provides many extension methods for filtering, grouping, sorting and many more which will make developers' lives easy.
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.
In a LINQ query expression, join operations are performed on object collections. Object collections cannot be "joined" in exactly the same way as two relational tables. In LINQ, explicit join clauses are only required when two source sequences are not tied by any relationship.
I've fixed it myself now. It was a schoolboy error passing too many parameters to the CreateQuery(... ) call. Paste the following code into the Dynamic.cs file within the DynamicQueryable class for a dynamic Join extension method. You can find the source for the DynamicQuery sample project at http://code.msdn.microsoft.com/csharpsamples.
Enjoy.
public static IQueryable Join(this IQueryable outer, IEnumerable inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values)
{
if (inner == null) throw new ArgumentNullException("inner");
if (outerSelector == null) throw new ArgumentNullException("outerSelector");
if (innerSelector == null) throw new ArgumentNullException("innerSelector");
if (resultsSelector == null) throw new ArgumentNullException("resultsSelctor");
LambdaExpression outerSelectorLambda = DynamicExpression.ParseLambda(outer.ElementType, null, outerSelector, values);
LambdaExpression innerSelectorLambda = DynamicExpression.ParseLambda(inner.AsQueryable().ElementType, null, innerSelector, values);
ParameterExpression[] parameters = new ParameterExpression[] {
Expression.Parameter(outer.ElementType, "outer"), Expression.Parameter(inner.AsQueryable().ElementType, "inner") };
LambdaExpression resultsSelectorLambda = DynamicExpression.ParseLambda(parameters, null, resultsSelector, values);
return outer.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Join",
new Type[] {outer.ElementType, inner.AsQueryable().ElementType, outerSelectorLambda.Body.Type, resultsSelectorLambda.Body.Type },
outer.Expression, inner.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(innerSelectorLambda), Expression.Quote(resultsSelectorLambda)));
}
//The generic overload.
public static IQueryable<T> Join<T>(this IQueryable<T> outer, IEnumerable<T> inner, string outerSelector, string innerSelector, string resultsSelector, params object[] values)
{
return (IQueryable<T>)Join((IQueryable)outer, (IEnumerable)inner, outerSelector, innerSelector, resultsSelector, values);
}
You can install the nuget package of System.Linq.Dynamic.Core - https://github.com/StefH/System.Linq.Dynamic.Core
This has the join method implemented along with various other helper methods.
Using this library you can do a simple join in the following the way
myContext.TableA.Join(myContext.TableB,'Id','TableAId','outer',null)
in the result selector outer
and inner
are key words to access the result of the join.
Using a key with multiple properties and/or selecting a result with multiple properties can be done in the following way
myContext.TableA.Join(myContext.TableB,'new (Id as key1,Code as key2)','new (TableAId as key1,AnotherCol as key2)','new(outer.Id,inner.Desc)',null)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With