MudDataGrid中FilterDefinitions与SortDefinitions在ServerData函数内失效问题
问题描述
尝试用IQueryable实现动态排序与过滤时遇到两个问题:
- 初始代码中
Where和OrderBy出现编译错误,提示无法将IEnumerable<GreenPaperItem>转换为IQueryable<GreenPaperItem>:
GridState<GreenPaperItem> state = null; private async Task<GridData<GreenPaperItem>> LoadData(GridState<GreenPaperItem> state) { this.state = state; var query = context.GreenPaperItems.AsQueryable(); if (state.FilterDefinitions != null && state.FilterDefinitions.Count() > 0) { foreach (var filter in state.FilterDefinitions) query = query.Where(filter.GenerateFilterFunction()); } if (state.SortDefinitions != null && state.SortDefinitions.Count() > 0) { foreach (var sort in state.SortDefinitions) query = query.OrderBy(sort.SortFunc); } else { query = query.OrderBy(w => w.Date); } int count = query.Count(); var items = query.Skip(state.PageSize * state.Page).Take(state.PageSize) .ToList<GreenPaperItem>(); GridData<GreenPaperItem> data = new() { Items = items, TotalItems = count }; return data; }
- 修改为包装委托的写法后,编译通过但运行时EF无法将表达式转换为SQL:
if (state.FilterDefinitions != null && state.FilterDefinitions.Count() > 0) { foreach (var filter in state.FilterDefinitions) query = query.Where(it => filter.GenerateFilterFunction(null)(it)); } if (state.SortDefinitions != null && state.SortDefinitions.Count() > 0) { foreach (var sort in state.SortDefinitions) query = query.OrderBy(it => sort.SortFunc(it)); } else { query = query.OrderBy(w => w.Date); }
核心原因
- 编译错误:
IQueryable.Where/OrderBy需要接收Expression<Func<...>>类型的参数,而你的GenerateFilterFunction()和SortFunc返回的是普通Func<...>委托。此时编译器会调用Enumerable.Where/OrderBy(针对IEnumerable的扩展方法),返回IEnumerable类型,无法直接赋值给IQueryable变量,导致类型转换错误。 - 运行时错误:将委托调用包装在表达式树中后,EF无法解析这种嵌套的委托调用逻辑,无法将其转换为对应的SQL语句,因此执行时抛出异常。
解决方案
1. 修正过滤逻辑
确保过滤逻辑传递的是Expression<Func<GreenPaperItem, bool>>而非普通委托:
方案A:修改GenerateFilterFunction返回表达式树
如果可以修改FilterDefinition类的GenerateFilterFunction方法,让它直接返回Expression<Func<GreenPaperItem, bool>>,代码可直接正常运行:
if (state.FilterDefinitions != null && state.FilterDefinitions.Any()) { foreach (var filter in state.FilterDefinitions) { var filterExpr = filter.GenerateFilterFunction(); // 返回Expression<Func<GreenPaperItem, bool>> query = query.Where(filterExpr); } }
方案B:用LinqKit扩展解析委托表达式
如果无法修改GenerateFilterFunction,可以使用LinqKit库的AsExpandable()方法让EF支持委托表达式的解析:
- 安装LinqKit NuGet包
- 修改代码:
// 先调用AsExpandable()启用表达式扩展 var query = context.GreenPaperItems.AsQueryable().AsExpandable(); if (state.FilterDefinitions != null && state.FilterDefinitions.Any()) { foreach (var filter in state.FilterDefinitions) { Func<GreenPaperItem, bool> filterFunc = filter.GenerateFilterFunction(); // 将委托包装为表达式,LinqKit会自动展开解析 Expression<Func<GreenPaperItem, bool>> filterExpr = x => filterFunc(x); query = query.Where(filterExpr); } }
2. 修正排序逻辑
同样需要传递Expression<Func<GreenPaperItem, TKey>>给OrderBy/ThenBy。如果你的SortDefinition存储的是字段名而非表达式,可以通过反射动态构建排序表达式:
if (state.SortDefinitions != null && state.SortDefinitions.Any()) { IOrderedQueryable<GreenPaperItem> orderedQuery = null; foreach (var sort in state.SortDefinitions) { // 构建参数表达式:x => x.FieldName var parameter = Expression.Parameter(typeof(GreenPaperItem), "x"); var property = Expression.Property(parameter, sort.FieldName); // 假设SortDefinition有FieldName属性 var sortExpr = Expression.Lambda(property, parameter); // 首次排序用OrderBy/OrderByDescending,后续用ThenBy/ThenByDescending if (orderedQuery == null) { orderedQuery = sort.IsAscending ? Queryable.OrderBy(query, sortExpr as dynamic) : Queryable.OrderByDescending(query, sortExpr as dynamic); } else { orderedQuery = sort.IsAscending ? Queryable.ThenBy(orderedQuery, sortExpr as dynamic) : Queryable.ThenByDescending(orderedQuery, sortExpr as dynamic); } } query = orderedQuery; } else { query = query.OrderBy(w => w.Date); }
完整修正后的代码示例
private async Task<GridData<GreenPaperItem>> LoadData(GridState<GreenPaperItem> state) { var query = context.GreenPaperItems.AsQueryable().AsExpandable(); // 若用LinqKit则加AsExpandable() // 动态过滤 if (state.FilterDefinitions != null && state.FilterDefinitions.Any()) { foreach (var filter in state.FilterDefinitions) { var filterExpr = filter.GenerateFilterFunction() is Expression<Func<GreenPaperItem, bool>> expr ? expr : Expression.Lambda<Func<GreenPaperItem, bool>>(x => ((Func<GreenPaperItem, bool>)filter.GenerateFilterFunction())(x)); query = query.Where(filterExpr); } } // 动态排序 if (state.SortDefinitions != null && state.SortDefinitions.Any()) { IOrderedQueryable<GreenPaperItem> orderedQuery = null; foreach (var sort in state.SortDefinitions) { var parameter = Expression.Parameter(typeof(GreenPaperItem), "x"); var property = Expression.Property(parameter, sort.FieldName); var sortExpr = Expression.Lambda(property, parameter); orderedQuery = orderedQuery == null ? (sort.IsAscending ? Queryable.OrderBy(query, sortExpr as dynamic) : Queryable.OrderByDescending(query, sortExpr as dynamic)) : (sort.IsAscending ? Queryable.ThenBy(orderedQuery, sortExpr as dynamic) : Queryable.ThenByDescending(orderedQuery, sortExpr as dynamic)); } query = orderedQuery; } else { query = query.OrderBy(w => w.Date); } int count = await query.CountAsync(); // 改用异步方法提升性能 var items = await query.Skip(state.PageSize * state.Page).Take(state.PageSize).ToListAsync(); return new GridData<GreenPaperItem> { Items = items, TotalItems = count }; }
内容的提问来源于stack exchange,提问作者mz1378
相关产品推荐
相关产品推荐

