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

如何使用Dapper从动态变更列的表中提取数据

问题描述

现有Tasks表和Codes表,初始结构如下:

Tasks表:

IDTaskname
12D
23D

Codes表:

IDCodenameFor2DFor3D
12D10
23D01

用户可通过前端按钮在Tasks表添加新条目,对应Codes表需新增列,例如新增4D任务后,Codes表会新增For4D列。目前已能通过Dapper实现列添加操作,但无法确定用户会添加多少新任务,因此不知如何编写查询并使用Dapper提取表中数据返回至前端。现有如下DqcDto类,但无法适配新增列:

public class DqcDto
{
    public string? DqcCode { get; set; }
    public string? DqcDescription { get; set; }
    public string Project { get; set; }
    public bool? IsFor3D { get; set; }
    public bool? IsFor2D { get; set; }
}
解决方案

针对动态列的适配问题,给你三个可行方案:

1. 直接用Dynamic类型快速解决

Dapper支持返回dynamic类型,无需固定DTO,自动匹配所有查询列:

using (var conn = new SqlConnection(yourConnString))
{
    var sql = "SELECT Codename AS DqcCode, DqcDescription, Project, For2D, For3D, For4D FROM Codes";
    var data = conn.Query<dynamic>(sql).ToList();
    // 直接序列化data返回前端即可,前端能拿到所有列
}

优点是代码简单,无需修改结构;缺点是编译时无类型检查。

2. 动态构建DTO和查询语句

先从Tasks表获取所有任务名,动态生成查询字段和映射:

// 第一步:获取所有任务
var tasks = conn.Query<TaskDto>("SELECT Taskname FROM Tasks").ToList();
// 第二步:构建动态列的查询别名(比如For2D → IsFor2D)
var taskColumns = tasks.Select(t => $"For{t.Taskname} AS IsFor{t.Taskname}").ToList();
// 第三步:拼接完整SQL
var sql = $"SELECT Codename AS DqcCode, DqcDescription, Project, {string.Join(", ", taskColumns)} FROM Codes";

// 第四步:用ExpandoObject动态存储结果
var results = new List<ExpandoObject>();
using (var reader = conn.ExecuteReader(sql))
{
    while (reader.Read())
    {
        var expando = new ExpandoObject();
        var dict = (IDictionary<string, object>)expando;
        // 固定字段赋值
        dict["DqcCode"] = reader["DqcCode"];
        dict["DqcDescription"] = reader["DqcDescription"];
        dict["Project"] = reader["Project"];
        // 动态字段赋值
        foreach (var task in tasks)
        {
            var colName = $"IsFor{task.Taskname}";
            dict[colName] = Convert.ToBoolean(reader[colName]);
        }
        results.Add(expando);
    }
}

这种方式既能保留类型语义,又能适配动态列,返回的ExpandoObject可直接序列化为JSON给前端。

3. 重构数据库结构(长期最优解)

动态新增列的设计违反数据库范式,建议改成关联表结构:

  • 新增CodeTaskRelations表:
CodeIDTaskIDIsApplicable
111
221
  • 新增任务时只需往Tasks表加条目,无需修改Codes表结构
  • 查询时通过关联获取数据:
var sql = @"SELECT c.Codename AS DqcCode, c.DqcDescription, c.Project, t.Taskname, r.IsApplicable
            FROM Codes c
            LEFT JOIN CodeTaskRelations r ON c.ID = r.CodeID
            LEFT JOIN Tasks t ON r.TaskID = t.ID";
var data = conn.Query(sql).ToList();

这种结构更易维护,扩展性更强,避免后续因动态列带来的各种问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:06:04