ASP.NET Core中基于Dynamic LINQ从对象动态过滤数据的问题
问题
我正在开发ASP.NET Core项目,需要基于动态生成的条件从内存中的jsonRecords对象筛选数据,最终返回筛选后数据的指定属性列表。目前代码是直接查询数据库,我需要改成从内存对象获取数据,同时保留原有的动态条件生成逻辑。
现有逻辑说明:
- 项目中有
JsonEditorContext,但现在不再直接查询其jsonsDbSet,改用内存中的List<JsonModel>类型集合jsonRecords - 接收
ListInput类型的输入参数,该对象包含一个ListData对象列表,用于生成筛选条件 - 通过
BuildWhereClause方法基于ListData中的非空值动态构建WHERE子句,同时识别倒数第二个非空属性,用于后续提取指定属性 - 原代码执行SQL查询并返回结果,现在需要改为内存LINQ查询
原代码
using System.Linq.Dynamic.Core; public IActionResult GetList([FromBody] ListInput input) { var queryComponent = BuildWhereClause(input.Data); string whereClause = queryComponent.whereClause; string requiredAttribute = queryComponent.nextToLastNonNullValue; var result = ExecuteSqlQuery(whereClause, requiredAttribute); return new ObjectResult(result); } private dynamic BuildWhereClause(List<ListData> data) { List<string> conditions = new List<string>(); string nextToLastNonNullValue = null; List<string> filteredRecord1 = null; foreach (var item in data) { var properties = item.GetType().GetProperties(); Console.WriteLine(properties.Length); for (int i = properties.Length-1; i >= 0; i--) { var value = properties[i].GetValue(item); if (value != null) { if (nextToLastNonNullValue == null) { nextToLastNonNullValue = properties[i + 1].Name; } } } foreach (var prop in item.GetType().GetProperties()) { var value = prop.GetValue(item); if (value != null) { string condition = $"{prop.Name} = '{value}'"; conditions.Add(condition); } } } if (conditions.Count == 0) { return (whereClause: string.Empty, nextToLastNonNullValue); } string whereClause = string.Join(" AND ", conditions); return (whereClause, nextToLastNonNullValue); } private dynamic ExecuteSqlQuery(string whereClause, string requireAttribute) { string sqlQuery = $"SELECT * FROM jsons"; if (!string.IsNullOrEmpty(whereClause)) { sqlQuery += $" WHERE {whereClause}"; } var jsonModels = _jsonsContext.jsons.FromSqlRaw<JsonModel>(sqlQuery).ToList(); // 需要替换这部分为内存查询 var attributes = requireAttribute.Split(','); var data = new Dictionary<string, List<object>>(); foreach (var attribute in attributes) { var distinctValues = jsonModels.Select(model => GetPropertyValue(model, attribute)).ToList().Distinct().ToList(); data[attribute] = distinctValues; } return new{data}; } private object GetPropertyValue(JsonModel model, string propertyName) { var property = typeof(JsonModel).GetProperty(propertyName); if (property != null) { return property.GetValue(model); } return null; }
解决方案
核心修改是将数据库查询替换为内存集合的Dynamic LINQ查询,同时调整条件构建的细节以适配内存查询逻辑。
假设jsonRecords是预先加载到内存中的List<JsonModel>集合,修改后的代码如下:
using System.Linq.Dynamic.Core; // 假设这是内存中的数据集合,根据实际情况初始化或注入 private List<JsonModel> jsonRecords; public IActionResult GetList([FromBody] ListInput input) { var queryComponent = BuildWhereClause(input.Data); string whereClause = queryComponent.whereClause; string requiredAttribute = queryComponent.nextToLastNonNullValue; var result = ExecuteInMemoryQuery(whereClause, requiredAttribute); return new ObjectResult(result); } // 优化后的条件构建方法,修复越界问题并适配内存查询 private (string whereClause, string nextToLastNonNullValue) BuildWhereClause(List<ListData> data) { List<string> conditions = new List<string>(); string nextToLastNonNullValue = null; foreach (var item in data) { var properties = item.GetType().GetProperties(); // 从后往前查找倒数第二个非空属性,增加越界判断 for (int i = properties.Length - 1; i >= 0; i--) { var value = properties[i].GetValue(item); if (value != null && nextToLastNonNullValue == null) { if (i + 1 < properties.Length) { nextToLastNonNullValue = properties[i + 1].Name; } break; } } // 根据属性类型构建条件,避免数值类型错误 foreach (var prop in item.GetType().GetProperties()) { var value = prop.GetValue(item); if (value != null) { string condition = prop.PropertyType == typeof(string) ? $"{prop.Name} = '{value}'" : $"{prop.Name} = {value}"; conditions.Add(condition); } } } string whereClause = conditions.Count == 0 ? string.Empty : string.Join(" AND ", conditions); return (whereClause, nextToLastNonNullValue); } // 替换为内存查询方法 private dynamic ExecuteInMemoryQuery(string whereClause, string requireAttribute) { IQueryable<JsonModel> query = jsonRecords.AsQueryable(); // 应用动态WHERE子句 if (!string.IsNullOrEmpty(whereClause)) { query = query.Where(whereClause); } var jsonModels = query.ToList(); var attributes = requireAttribute?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>(); var data = new Dictionary<string, List<object>>(); foreach (var attribute in attributes) { var distinctValues = jsonModels.Select(model => GetPropertyValue(model, attribute)) .Where(v => v != null) .Distinct() .ToList(); data[attribute] = distinctValues; } return new { data }; } // 保留属性获取方法 private object GetPropertyValue(JsonModel model, string propertyName) { var property = typeof(JsonModel).GetProperty(propertyName); return property?.GetValue(model); }
关键修改点
- 数据源替换:将数据库查询改为内存集合的
AsQueryable(),使用Dynamic LINQ的Where方法应用动态条件 - 边界修复:在查找倒数第二个非空属性时增加越界判断,避免
IndexOutOfRangeException - 条件适配:根据属性类型判断是否用单引号包裹值,解决数值类型条件的语法错误
- 空值处理:提取属性值时过滤空值,同时处理
requireAttribute为空的情况,避免异常 - 性能优化:内存查询避免了数据库往返,适合数据量不大的场景
内容的提问来源于stack exchange,提问作者yadav priya
相关产品推荐
相关产品推荐

