Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用字段类型的泛型筛选构建动态Where子句_C#_Linq - Fatal编程技术网

C# 使用字段类型的泛型筛选构建动态Where子句

C# 使用字段类型的泛型筛选构建动态Where子句,c#,linq,C#,Linq,这个问题源于我发布的另一个封闭的问题 我有以下电话 var query = _context.Listings.AsQueryable(); query = query.WhereEqualIfSpecified(x => x.HasBalcony, true); query = query.ApplyRangeFilter(x => x.BedroomsAvailable, 1, 9); query = query.A

这个问题源于我发布的另一个封闭的问题

我有以下电话

        var query = _context.Listings.AsQueryable();
        query = query.WhereEqualIfSpecified(x => x.HasBalcony, true);
        query = query.ApplyRangeFilter(x => x.BedroomsAvailable, 1, 9);
        query = query.ApplyRangeFilter(x => x.Baths, 1.0, 2.5);
        query = query.ApplyRangeFilter(x => x.Price, 1000.00, 2000.00);
        var listings = query.ToList();
我想将
WhereEqualIfSpecified
设置为泛型,这样它不仅适用于bools,而且一旦我将方法更改为following

    public static IQueryable<T> WhereEqualIfSpecified<T>(this IQueryable<T> query, Expression<Func<T, T>> fieldExpression, T filterValue)
    {
        return filterValue is null
            ? query
            : query.Where(fieldExpression.Compose(value => value.Equals(filterValue)));
    }

简而言之,我希望
WhereEqualIfSpecified
ApplyRangeFilter
都是泛型的,这样它就可以接受任何类型,而不是使用重载函数

您还需要一个泛型类型。在字段表达式中,表示func接受一个
T
并返回一个
T
表达式字段表达式
。但是它应该使用
T
并返回其他类型

请注意,您需要稍微更改调用,以使最小/最大值类型与属性类型匹配:
query=query.ApplyRangeFilter(x=>x.Price,1000M,2000M)


然而,数据列表似乎来自EF数据获取。请注意,这些类型的复杂筛选要求在客户端筛选数据,即获取所有数据,然后在应用程序中执行查询。如果有大量数据,这将是非常缓慢和昂贵的。

我已经修复了指定为您答案的Whereequalifs,我试图解决ApplyRangeFilter过载的问题,但似乎我可以这样做,而不是复杂的通用版本使用更复杂的
ApplyRangeFilter
编辑我的答案。如果有效,请将其标记为正确的解决方案。:-)上面的结果是内存中的过滤器vs sql,这是我试图避免的,您必须使查询更加简单,以便在数据库服务器上执行查询。所以这是你的问题,你要么关闭这个(根本没有提到),要么(最好)打开一个新的。但简单地说;你不能做任何表达式魔术而期望它变成一个SQL查询。我将在第一部分中标记这个答案,并在没有重载的情况下找出如何处理第二个答案
public partial class Listing
{

    public decimal? Price { get; set; }
    public int? BedroomsAvailable { get; set; }
    public double? Baths { get; set; }

    public bool? HasBalcony { get; set; }
    public bool? HasElevator { get; set; }

}
public static class ExtensionMethods
{

    public static IQueryable<T> WhereEqualIfSpecified<T>(this IQueryable<T> query, Expression<Func<T, bool?>> fieldExpression, bool? filterValue)
    {
        return filterValue is null
            ? query
            : query.Where(fieldExpression.Compose(value => value.Equals(filterValue)));
    }



    public static IQueryable<T> ApplyRangeFilter<T>(this IQueryable<T> query, Expression<Func<T, int?>> filter, int? minValue, int? maxValue)
    {
        if (minValue is null && maxValue is null) return query;

        if (maxValue != null && minValue != null)
        {
            return minValue == maxValue?
                 query.Where(filter.Compose(value => value.Equals(minValue))):
             query.Where(filter.Compose(value => value >= minValue && value <= maxValue));

        }

        return query.Where(maxValue != null ? filter.Compose(value => value <= maxValue) : filter.Compose(value => value >= minValue));
    }


    //copied from https://stackoverflow.com/questions/37602729/convert-linq-expression-obj-obj-prop-into-parent-parent-obj-prop/37602870#37602870
    public static Expression<Func<T, TResult>> Compose<T, TIntermediate, TResult>(
        this Expression<Func<T, TIntermediate>> first,
        Expression<Func<TIntermediate, TResult>> second)
    {
        return Expression.Lambda<Func<T, TResult>>(
            second.Body.Replace(second.Parameters[0], first.Body),
            first.Parameters[0]);
    }

    public class ReplaceVisitor : ExpressionVisitor
    {
        private readonly Expression from, to;
        public ReplaceVisitor(Expression from, Expression to)
        {
            this.from = from;
            this.to = to;
        }

        public override Expression Visit(Expression ex)
        {
            return ex == @from ? to : base.Visit(ex);
        }
    }

    public static Expression Replace(this Expression ex,
        Expression from,
        Expression to)
    {
        return new ReplaceVisitor(from, to).Visit(ex);
    }

}
public static IQueryable<TItem> WhereEqualIfSpecified<TItem, TFilterValue>(this IQueryable<TItem> query, Expression<Func<TItem, TFilterValue>> fieldExpression, TFilterValue filterValue)
{
    return filterValue is null
        ? query
        : query.Where(fieldExpression.Compose(value => value.Equals(filterValue)));
}
public static IQueryable<TItem> ApplyRangeFilter<TItem, TValue>(this IQueryable<TItem> query, Expression<Func<TItem, TValue?>> filter, TValue? minValue, TValue? maxValue)
    where TValue: struct, IComparable
{
    if (minValue is null && maxValue is null) return query;

    if (maxValue != null && minValue != null)
    {
        return minValue.Value.CompareTo(maxValue.Value) == 0
            ? query.Where(filter.Compose(value => value != null && value.Value.Equals(minValue.Value)))
            : query.Where(filter.Compose(value => value != null && value.Value.CompareTo(minValue.Value) >= 0 && value.Value.CompareTo(maxValue.Value) <= 0));
    }

    return query.Where(maxValue != null
        ? filter.Compose(value => value != null && value.Value.CompareTo(maxValue.Value) <= 0) 
        : filter.Compose(value => value != null && value.Value.CompareTo(minValue.Value) >= 0));
}