如何对Dapper返回的dynamic动态集合使用OrderBy按动态字段排序
Dapper动态返回结果按未知字段排序方案
Dapper返回的DapperRow动态对象本质实现了IDictionary<string, object>接口,所有查询返回的字段都以键值对形式存在内部字典中,不需要提前在代码里定义字段对应的属性,直接通过字段名字符串索引取值就能完成排序。
单字段快速排序
比如要按示例里的Almuerzo字段排序,直接通过字典索引取值即可,注意你当前返回的数值类字段都是字符串格式,必须先转成数值类型再排序,否则会按字符串规则排序(比如字符串比较下"2"会排在"1437"后面,结果错误):
using System.Collections.Generic; using System.Linq; // 按Almuerzo升序 var sortedResult = reporte .OrderBy(r => int.Parse((string)((IDictionary<string, object>)r)["Almuerzo"])) .ToList(); // 降序把OrderBy换成OrderByDescending即可
通用动态排序封装
如果需要支持运行时传入任意字段名排序,可以封装通用方法,自动处理值类型转换和字段校验:
using System.Collections.Generic; using System.Linq; using System.Globalization; public List<dynamic> SortDapperRows(IEnumerable<dynamic> dapperRows, string sortField, bool isDescending = false) { // 空值和字段合法性校验 var firstRow = dapperRows.FirstOrDefault() as IDictionary<string, object>; if (firstRow == null) return new List<dynamic>(); if (!firstRow.ContainsKey(sortField)) throw new ArgumentException($"字段{sortField}不存在于查询结果中"); Func<dynamic, object> sortKeySelector = row => { var rowDict = (IDictionary<string, object>)row; var rawValue = (string)rowDict[sortField]; // 适配当前数据格式:小数用逗号做分隔符,比如106800,00 if (rawValue.Contains(',')) { return decimal.Parse(rawValue.Replace(',', '.'), CultureInfo.InvariantCulture); } // 整数字段直接转int if (int.TryParse(rawValue, out int intValue)) return intValue; // 字符串类字段(比如centroCosto)直接返回原值排序 return rawValue; }; return isDescending ? dapperRows.OrderByDescending(sortKeySelector).ToList() : dapperRows.OrderBy(sortKeySelector).ToList(); }
封装后调用不需要关心字段是固定字段还是动态字段,直接传字段名即可:
// 按动态字段Almuerzo升序 var sortByAlmuerzo = SortDapperRows(reporte, "Almuerzo"); // 按动态字段Cena降序 var sortByCenaDesc = SortDapperRows(reporte, "Cena", isDescending: true); // 固定字段也能正常用,比如按valorTotal升序 var sortByTotal = SortDapperRows(reporte, "valorTotal");
补充说明
- 如果需要获取所有动态字段的名称,把任意一行转成
IDictionary<string, object>后取.Keys属性就能拿到当前查询返回的全部字段名,不需要额外查询数据库表结构。 - 不要尝试用动态属性表达式(比如
r => r.XXX)的方式做通用动态排序,这种写法的属性名是写死在编译期的,没法支持运行时才知道字段名的场景,字典索引是Dapper场景下最稳定、性能最好的方案。
内容的提问来源于stack exchange,提问作者jstuardo
相关产品推荐
相关产品推荐

