You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core中基于Dynamic LINQ从对象动态过滤数据的问题

问题

我正在开发ASP.NET Core项目,需要基于动态生成的条件从内存中的jsonRecords对象筛选数据,最终返回筛选后数据的指定属性列表。目前代码是直接查询数据库,我需要改成从内存对象获取数据,同时保留原有的动态条件生成逻辑。

现有逻辑说明:

  • 项目中有JsonEditorContext,但现在不再直接查询其jsons DbSet,改用内存中的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);
}

关键修改点

  1. 数据源替换:将数据库查询改为内存集合的AsQueryable(),使用Dynamic LINQ的Where方法应用动态条件
  2. 边界修复:在查找倒数第二个非空属性时增加越界判断,避免IndexOutOfRangeException
  3. 条件适配:根据属性类型判断是否用单引号包裹值,解决数值类型条件的语法错误
  4. 空值处理:提取属性值时过滤空值,同时处理requireAttribute为空的情况,避免异常
  5. 性能优化:内存查询避免了数据库往返,适合数据量不大的场景

内容的提问来源于stack exchange,提问作者yadav priya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 03:44:56