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

ASP.NET Core中如何通过LINQ to Entities获取动态列数据?

问题根源

你当前的代码中,select ($"new {string.Join(", ", columns)} ")只是将用户传入的列名拼接成字符串返回,并没有真正从Children和Centers实体中提取对应列的实际数据,因此返回的只是列名字符串列表,而非报表需要的业务数据。

解决方案

以下提供两种可行的修改方案,你可以根据项目需求选择:

方案1:使用反射构建动态对象(无需额外依赖)

这种方式通过手动反射实体属性,将指定列的数据封装到动态对象中,适合小型场景或无法引入第三方库的情况。

修改后的代码

public async Task<Collection_Response<dynamic>> GetReportDataAsync(int Report_Type, List<string> columns, DateTime Start_Date, DateTime End_Date, string Lang)
{
    Collection_Response<dynamic> result = new Collection_Response<dynamic>()
    {
        Is_Success = false,
        Messages = new List<Message_Item>()
    };

    try
    {
        // 先执行基础关联和过滤查询,保留关联的两个实体
        var baseQuery = from p in db.Children
                        join e in db.Centers on p.Center_ID equals e.Center_ID
                        where p.Joining_Date >= Start_Date && p.Joining_Date <= End_Date
                        select new { Child = p, Center = e };

        // 异步获取查询结果
        var dataList = await baseQuery.ToListAsync();

        // 转换为仅包含指定列的动态对象列表
        var reportData = new List<dynamic>();
        foreach (var item in dataList)
        {
            var expando = (ExpandoObject)new ExpandoObject();
            var expandoDict = expando as IDictionary<string, object>;

            foreach (var column in columns)
            {
                // 优先从Child实体取属性
                var childProp = item.Child.GetType().GetProperty(column);
                if (childProp != null)
                {
                    expandoDict[column] = childProp.GetValue(item.Child);
                    continue;
                }

                // 从Center实体取属性
                var centerProp = item.Center.GetType().GetProperty(column);
                if (centerProp != null)
                {
                    expandoDict[column] = centerProp.GetValue(item.Center);
                    continue;
                }

                // 列名不存在时的处理(可根据需求调整,比如返回null或添加错误提示)
                expandoDict[column] = null;
            }
            reportData.Add(expando);
        }

        result.Data = reportData;
        result.Is_Success = true;
    }
    catch (Exception ex)
    {
        result.Messages.Add(new Message_Item() { Message = err.Handle_Exception(ex) });
    }
    return result;
}

方案2:使用System.Linq.Dynamic.Core实现动态查询(推荐)

通过第三方库直接构建动态LINQ查询,在数据库层面就只返回需要的列,性能更优,适合数据量较大的场景。

步骤1:安装依赖包

在NuGet包管理器中安装System.Linq.Dynamic.Core:

Install-Package System.Linq.Dynamic.Core

修改后的代码

using System.Linq.Dynamic.Core;

public async Task<Collection_Response<dynamic>> GetReportDataAsync(int Report_Type, List<string> columns, DateTime Start_Date, DateTime End_Date, string Lang)
{
    Collection_Response<dynamic> result = new Collection_Response<dynamic>()
    {
        Is_Success = false,
        Messages = new List<Message_Item>()
    };

    try
    {
        // 【关键安全步骤】验证列名是否在白名单内,防止恶意列名导致的信息泄露
        var allowedColumns = new List<string> 
        { 
            "p.ChildID", "p.Name", "p.Joining_Date", 
            "e.Center_ID", "e.CenterName" 
        }; // 替换为实际允许访问的列名(需包含实体别名,比如p代表Children,e代表Centers)
        
        foreach (var column in columns)
        {
            if (!allowedColumns.Contains(column))
            {
                result.Messages.Add(new Message_Item() { Message = $"列名 {column} 不允许访问" });
                return result;
            }
        }

        // 构建动态select语句
        var selectClause = string.Join(", ", columns);

        // 执行动态查询
        var reportData = await db.Children
            .Join(db.Centers, p => p.Center_ID, e => e.Center_ID, (p, e) => new { p, e })
            .Where("p.Joining_Date >= @0 && p.Joining_Date <= @1", Start_Date, End_Date)
            .Select(selectClause)
            .ToDynamicListAsync();

        result.Data = reportData;
        result.Is_Success = true;
    }
    catch (Exception ex)
    {
        result.Messages.Add(new Message_Item() { Message = err.Handle_Exception(ex) });
    }
    return result;
}
重要注意事项
  • 安全性:无论使用哪种方案,必须对用户传入的列名进行白名单验证,禁止访问敏感字段(比如密码、内部ID等),防止信息泄露或恶意攻击。
  • 返回类型调整:将原返回类型Collection_Response<string>改为Collection_Response<dynamic>,因为需要返回包含多列数据的对象,而非单一字符串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:42:10