使用.Set()而不是.Set <t>()从基于类型的DbSet中进行选择

时间:2016-10-24 17:57:30

标签: entity-framework-6 dbset

我正在创建一个高级搜索,将OData表达式转换为.NET表达式树(Expression<Func<T, bool>>)。我将此表达式作为谓词传递给我的EF6 .Select()方法,并按预期工作。

但是,在实现此功能时,我发现LINQ方法仅适用于IQueryable<TSource>。这适用于.Set<T>(),但我不知道运行时的类型,因此我需要使用.Set()

我可能会使用反射调用.Set<T>()然后调用它,但这看起来有点像黑客,所以我宁愿直接通过.Set()来做,如果可能的话。< / p>

1 个答案:

答案 0 :(得分:1)

如果我理解正确,您有LambdaExpression而不是Expression<Func<T, bool>>,并且您希望将其用作Where,而是IQueryableDbSet类实现而不是IQueryable<T>

您需要知道的是,IQueryable<T>扩展方法只会将MethodCallExpression发送到查询表达式树中相应的Queryable方法。

例如,要模仿Where上的SelectIQueryable,您可以使用以下自定义扩展程序:

public static class QueryableExtensions
{
    public static IQueryable Where(this IQueryable source, LambdaExpression predicate)
    {
        var expression = Expression.Call(
            typeof(Queryable), "Where",
            new Type[] { source.ElementType },
            source.Expression, Expression.Quote(predicate));
        return source.Provider.CreateQuery(expression);
    }

    public static IQueryable Select(this IQueryable source, LambdaExpression selector)
    {
        var expression = Expression.Call(
            typeof(Queryable), "Select",
            new Type[] { source.ElementType, selector.Body.Type },
            source.Expression, Expression.Quote(selector));
        return source.Provider.CreateQuery(expression);
    }
}

您可以对所需的其他Queryable方法执行类似操作。

更新:由于您感兴趣,以下是使用表达式原型获取通用方法定义并从中构造泛型方法的示例:

public static class QueryableExtensions
{
    static MethodInfo QueryableMethod<T>(this Expression<Func<IQueryable<object>, T>> prototype, params Type[] types)
    {
        return ((MethodCallExpression)prototype.Body).Method
            .GetGenericMethodDefinition()
            .MakeGenericMethod(types);
    }

    public static IQueryable Where(this IQueryable source, LambdaExpression predicate)
    {
        var expression = Expression.Call(
            QueryableMethod(q => q.Where(x => true), source.ElementType),
            source.Expression, Expression.Quote(predicate));
        return source.Provider.CreateQuery(expression);
    }

    public static IQueryable Select(this IQueryable source, LambdaExpression selector)
    {
        var expression = Expression.Call(
            QueryableMethod(q => q.Select(x => 1), source.ElementType, selector.Body.Type),
            source.Expression, Expression.Quote(selector));
        return source.Provider.CreateQuery(expression);
    }
}