使用Dynamic LINQ的Skip和Take时抛出“Unknown LINQ expression of type Dynamic”异常
在ASP.NET MVC 5.2.9中使用System.Linq.Dynamic.Core 1.2.20实现分页的问题解决办法
问题场景
在ASP.NET MVC(5.2.9)项目中,使用System.Linq.Dynamic.Core(1.2.20)构建报表生成器时,大部分功能正常,但通过SetDynamic方法构建的查询无法使用Skip和Take实现分页,调用这两个方法会抛出异常:Unknown LINQ expression of type 'Dynamic'。移除Skip和Take后查询可正常返回结果,但丢失分页功能。
排查发现,SetDynamic返回IQueryable<object>,而使用强类型的Set<T>开头的相同查询可以正常使用Skip和Take。
原代码示例:
_context.SetDynamic("ENTITY_NAME") .Where(_parsingConfig, WHERE_EXPRESSION) .OrderBy(_parsingConfig, ORDER_BY_EXPRESSION) .Skip(???)// 抛出异常 .Take(???)// 抛出异常 .Select(_parsingConfig, SELECT_EXPRESSION) .ToDynamicListAsync();
解决方案
方案一:使用Dynamic LINQ的字符串版Skip/Take扩展方法
System.Linq.Dynamic.Core提供了适配动态查询的Skip和Take扩展方法,支持传入字符串形式的表达式参数,替代原生LINQ的Skip(int)和Take(int)。修改代码如下:
// 假设pageIndex是当前页码,pageSize是每页条数 var skipCount = pageSize * (pageIndex - 1); _context.SetDynamic("ENTITY_NAME") .Where(_parsingConfig, WHERE_EXPRESSION) .OrderBy(_parsingConfig, ORDER_BY_EXPRESSION) .Skip(_parsingConfig, skipCount.ToString()) .Take(_parsingConfig, pageSize.ToString()) .Select(_parsingConfig, SELECT_EXPRESSION) .ToDynamicListAsync();
如果需要直接引用变量,也可以用Dynamic LINQ的变量引用语法:
_context.SetDynamic("ENTITY_NAME") .Where(_parsingConfig, WHERE_EXPRESSION) .OrderBy(_parsingConfig, ORDER_BY_EXPRESSION) .Skip(_parsingConfig, "@pageSize * (@pageIndex - 1)", new { pageSize, pageIndex }) .Take(_parsingConfig, "@pageSize", new { pageSize }) .Select(_parsingConfig, SELECT_EXPRESSION) .ToDynamicListAsync();
方案二:转换为IQueryableDynamic后使用原生分页方法
通过AsQueryableDynamic扩展方法,将IQueryable<object>转换为Dynamic LINQ专用的查询类型,这样原生的Skip和Take就能被正确解析:
using System.Linq.Dynamic.Core; // ... var dynamicQuery = _context.SetDynamic("ENTITY_NAME") .Where(_parsingConfig, WHERE_EXPRESSION) .OrderBy(_parsingConfig, ORDER_BY_EXPRESSION) .AsQueryableDynamic(); var pagedResult = await dynamicQuery .Skip(pageSize * (pageIndex - 1)) .Take(pageSize) .Select(_parsingConfig, SELECT_EXPRESSION) .ToDynamicListAsync();
方案三:内存分页(仅适合小数据量场景)
如果报表数据量不大,业务允许的情况下,可以先查询全量数据,再在内存中执行分页。注意这种方式会加载所有符合条件的数据到内存,大数据量下性能较差:
var fullData = await _context.SetDynamic("ENTITY_NAME") .Where(_parsingConfig, WHERE_EXPRESSION) .OrderBy(_parsingConfig, ORDER_BY_EXPRESSION) .Select(_parsingConfig, SELECT_EXPRESSION) .ToDynamicListAsync(); var pagedData = fullData.Skip(pageSize * (pageIndex - 1)).Take(pageSize).ToList();
内容的提问来源于stack exchange,提问作者Gup3rSuR4c
相关产品推荐
相关产品推荐

