如何使用C#中的表达式创建动态Lambda连接查询?

时间:2018-12-28 10:50:36

标签: c# lambda expression expression-trees

我是动态表达式查询的新手...

我想动态创建一个联接查询。在它下面的查询是我想要的等效动态查询:

var lstNums = new List<int> { 100, 101 }; 
var getAll = new StudenRepository().GetAll(); //Returns IQuerable<Student>

var query = getAll.Join(lstNums, a => a.StudentId, b => b, (a, b) => a).ToList(); 
  1. lstNums可以是任何原始数据类型的列表
  2. getAll包含IQuerable,这可以是任何实体的IQuerable
  3. query和整数列表联接后,List<Student>将包含getAll条记录。但是结果可以是任何实体列表。列表,即lstNum可以是原始数据类型的任何列表。

以下是我尝试过的内容:

public static IQueryable JoinQuery(this IQueryable outer, IEnumerable innerEntities, string firstEntityPropName, 
    Type typeSecondEntity, Type typeResultEntity, params object[] values)
{
    LambdaExpression outerSelectorLambda = DynamicLinq.DynamicExpression.ParseLambda(outer.ElementType, null, firstEntityPropName, values);

    ParameterExpression expnInput = Expression.Parameter(typeSecondEntity, "inner");
    ParameterExpression expnResult = Expression.Parameter(typeResultEntity, "outer");               

    return outer.Provider.CreateQuery(
       Expression.Call(
           typeof(Queryable), "Join",
           new Type[] { outer.ElementType, innerEntities.AsQueryable().ElementType, outerSelectorLambda.Body.Type, expnResult.Type },
           outer.Expression, innerEntities.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), expnInput,
           expnResult));
}

扩展方法:

public static IQueryable<T> JoinQuery<T>(this IQueryable outer, IEnumerable innerEntities, string firstEntityPropName, Type typeSecondEntity, Type typeResultEntity, params object[] values)
{
    return (IQueryable<T>)Extensions.JoinQuery((IQueryable)outer, (IEnumerable)innerEntities, firstEntityPropName, typeSecondEntity, typeResultEntity, values);
}

注意:我已经安装了System.Linq.Dynamic nuget软件包版本1.0.7用于动态linq表达式。

1 个答案:

答案 0 :(得分:2)

以下代码对我有用:

using DynamicLinq = System.Linq.Dynamic;
using LinqExpression = System.Linq.Expressions;

public static IQueryable JoinQuery(this IQueryable outer, IEnumerable innerEntities, string firstEntityPropName, 
    Type typeSecondEntity, Type typeResultEntity, params object[] values)
{
    if (innerEntities == null) throw new ArgumentNullException(nameof(innerEntities));
    if (firstEntityPropName == null) throw new ArgumentNullException(nameof(firstEntityPropName));
    if (typeSecondEntity == null) throw new ArgumentNullException(nameof(typeSecondEntity));
    if (typeResultEntity == null) throw new ArgumentNullException(nameof(typeResultEntity));

    LambdaExpression outerSelectorLambda = DynamicLinq.DynamicExpression.ParseLambda(outer.ElementType, null, firstEntityPropName, values);

    ParameterExpression expnInput = Expression.Parameter(typeSecondEntity, "inner");

    ParameterExpression[] parameters = new ParameterExpression[] {
    Expression.Parameter(outer.ElementType, "outer"), Expression.Parameter(innerEntities.AsQueryable().ElementType, "inner")
    };

    LambdaExpression selectorSecondEntity = DynamicLinq.DynamicExpression.ParseLambda(new ParameterExpression[] { expnInput }, typeSecondEntity, "inner");
    LambdaExpression selectorResult = DynamicLinq.DynamicExpression.ParseLambda(parameters, typeResultEntity, "outer");

    return outer.Provider.CreateQuery(
       Expression.Call(
           typeof(Queryable), "Join",
           new Type[] { outer.ElementType, innerEntities.AsQueryable().ElementType, outerSelectorLambda.Body.Type, selectorResult.Body.Type },
           outer.Expression, innerEntities.AsQueryable().Expression, Expression.Quote(outerSelectorLambda), Expression.Quote(selectorSecondEntity),
          Expression.Quote(selectorResult)));
}

扩展方法如下:

public static IQueryable<T> JoinQuery<T>(this IQueryable outer, IEnumerable innerEntities, string firstEntityPropName, Type typeSecondEntity, Type typeResultEntity, params object[] values)
{
    return (IQueryable<T>)Extensions.JoinQuery((IQueryable)outer, (IEnumerable)innerEntities, firstEntityPropName, typeSecondEntity, typeResultEntity, values);
}