【问题标题】:Custom LINQ Where clause not actually applying Where自定义 LINQ Where 子句实际上并未应用 Where
【发布时间】:2021-04-23 08:52:56
【问题描述】:

我有一个自定义过滤器表达式,用户可以将字典发送到我的 api,我将创建一个自定义 where 子句。我不是编写自定义 LINQ 的专家,所以如果有更好的方法,那就太好了。

所有这些都有效(没有错误),但它没有应用我的过滤,因此返回它可以找到的所有内容)

我在其中添加自定义过滤器的存储库调用(查看“FilterByString”区域) . _entities 是一个 DbSet

// This is in my contructor
private readonly DbSet<T2> _entities;
_entities = _context.Set<T2>();

public async Task<BasePagedResponse<T1>> PagedList(Guid companyId, int pageNumber, int pageSize, Dictionary<string, string> filterParameters, Expression<Func<T2, bool>> predicate, Func<IQueryable<T2>, IIncludableQueryable<T2, object>> including = null)
    {
        try
        {
            var modelList = await _entities
                                    .AsQueryable()
                                    .Where(predicate)
                                    .CustomInclude(including)
                                    .FilterByString(filterParameters)
                                    .Skip((pageNumber - 1) * pageSize)
                                    .Take(pageSize).ToListAsync();

            var mappedList = _mapper.Map<List<T1>>(modelList);
            var total = await GetTotalRecords(companyId);
            var pagedResult = new PagedResult<T1>(mappedList, total, pageNumber, pageSize);
            
            return new BasePagedResponse<T1>(pagedResult, true, null);
        }
        catch (SqlException ex)
        {
            return new BasePagedResponse<T1>(null, false, new[] { new Error(GlobalVariables.error_list, $"Error listing models-({typeof(T1).Name}). {ex.Message}") });
        }
    }

我的静态 SQL 助手,它接受源查询并附加我的自定义 Where 子句

 public static IQueryable<T> FilterByString<T>(this IQueryable<T> source, Dictionary<string, string> filterParameters = null)
    {
        if (filterParameters != null)
        {
            foreach (var keyValuePair in filterParameters)
            {
                source.Where(Filter<T>(keyValuePair.Key, keyValuePair.Value));
            }
        }

        return source;
    }

我的自定义“过滤器”(看起来很多,但它只是查找要过滤的字符串、bool 或 int 类型)

private static Expression<Func<T, bool>> Filter<T>(string propertyName, string queryText)
    {
        var parameter = Expression.Parameter(typeof(T), "entity");
        var getter = Expression.Property(parameter, propertyName);
        if (getter.Type == typeof(string))
        {
            var stringContainsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            var containsCall = Expression.Call(getter, stringContainsMethod,
                Expression.Constant(queryText, typeof(string)));
            return Expression.Lambda<Func<T, bool>>(containsCall, parameter);
        }
        if (getter.Type == typeof(int))
        {
            var stringEqualsMethod = typeof(int).GetMethod("Equals", new[] { typeof(int) });
            var equalsCall = Expression.Call(getter, stringEqualsMethod,
                Expression.Constant(value: Int32.Parse(queryText), typeof(Int32)));
            return Expression.Lambda<Func<T, bool>>(equalsCall, parameter);
        }
        if (getter.Type == typeof(bool))
        {
            var stringEqualsMethod = typeof(bool).GetMethod("Equals", new[] { typeof(bool) });
            var equalsCall = Expression.Call(getter, stringEqualsMethod,
                Expression.Constant(value: bool.Parse(queryText), typeof(bool)));
            return Expression.Lambda<Func<T, bool>>(equalsCall, parameter);
        }

        throw new Exception("No proper type defined for Filter Parameter. Supports only String, Int and Boolean");
    }

【问题讨论】:

  • 附带说明:构建处理所有过滤器的一个谓词(通过Expression.AndAlso)比执行.Where(...).Where(...).Where(...) - 即让您的Filter&lt;T&gt; API 采用Dictionary&lt;string, string&gt; 并执行循环inside,只返回一个谓词;在 C# 术语中,这是 where A &amp;&amp; B &amp;&amp; C 而不是 where A where B where C
  • 感谢您的建议。我会相应地更新我的代码

标签: c# linq


【解决方案1】:

这是一个装饰器 API,其中.Where(...)返回一个查询,该查询被组合成包含谓词,但不会改变原始 em>查询;你需要保留结果:

foreach (var keyValuePair in filterParameters)
{
    source = source.Where(Filter<T>(keyValuePair.Key, keyValuePair.Value));
    // ^^^^^
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2012-01-05
    • 2023-03-22
    • 2015-08-29
    相关资源
    最近更新 更多