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

C#从MySQL查询生成嵌套JSON的实现困扰

问题描述

我正在用C#从MySQL数据库取数据并生成嵌套JSON,目前写了以下代码,但没法实现数据嵌套,而且GetAlumnos方法里的codigoOferta参数完全没生效。我需要生成指定结构的嵌套JSON,每个学生的数据不同,得实现变量的嵌套关联。

现有代码

// 获取根级信息
public List<Root> GetRoot()
{
    using (var conexion = ObtenerConexion())
    {
        conexion.Open();
        var query = @"SELECT id AS Id, fullname AS NombreCurso,  MID(fullname, INSTR(fullname, ""RLAB""), 20) AS codigoOferta
                        FROM mo_course 
                        WHERE  MID(fullname, INSTR(fullname, ""RLAB""), 20) != '';";
        var resultado = conexion.Query<Root>(query);
        
        foreach (var item in resultado)
        {
            Root root = new Root();
            root.codigoOferta = item.codigoOferta;
            root.listaAlumnos = new List<ListaAlumno>();
            roots.Add(root);
            conexion.Close();
        }
        return roots;
    }
}

public List<ListaAlumno> GetAlumnos(string codigoOferta)
{
    using (var conexion = ObtenerConexion())
    {
        conexion.Open();
        var query = @"SELECT mo_role_assignments.userid AS Id, firstname AS Nombre, lastname AS Apellido, LEFT(mo_user.idnumber, LENGTH(mo_user.idnumber - 2)) AS rutAlumno,
                        RIGHT(mo_user.idnumber, 1) AS dvAlumno, email AS Correo, mo_course.fullname AS NombreCurso, mo_course.idnumber AS codigoOferta,
                        FROM_UNIXTIME(startdate) AS fechaInicio, FROM_UNIXTIME(enddate) AS fechaFin
                        FROM mo_course
                        INNER JOIN mo_context ON mo_context.instanceid = mo_course.id
                        INNER JOIN mo_role_assignments ON mo_context.id = mo_role_assignments.contextid
                        INNER JOIN mo_user ON (mo_role_assignments.userid = mo_user.id)";

        var resultado = conexion.Query<ListaAlumno>(query);
        foreach (var item in resultado)
        {
            ListaAlumno alumno = new ListaAlumno();
            alumno.codigoOferta = item.codigoOferta;
            alumno.rutAlumno = item.rutAlumno;
            alumno.dvAlumno = item.dvAlumno;
            alumno.tiempoConectividad = 0;
            alumno.estado = 0;
            alumno.porcentajeAvance = 0;
            alumno.fechaInicio = item.fechaInicio;
            alumno.fechaFin = item.fechaFin;
            alumno.fechaEjecucion = "";
            alumno.listaModulos = new List<ListaModulo>();
            listaAlumnos.Add(alumno);
        }
        conexion.Close();
    }
    return listaAlumnos;
}

期望的嵌套JSON结构

{
    "rutOtec": "9999999-9",
    "idSistema": 1350,
    "token": "AAAAAA-ASSS-DDDDd-8FFF-2FFFFFFFFD2",
    "codigoOferta": "RSJ-D444-555-666666",
    "codigoGrupo": "RSJ-D444-555-666666",
    "codigoEnvio": "RSJ-D444-555-666666",
    "listaAlumnos": [
        {
            "rutAlumno": 255544466,
            "dvAlumno": "4",
            "tiempoConectividad": 199112,
            "estado": 1,
            "porcentajeAvance": 99,
            "fechaInicio": "2022-07-28",
            "fechaFin": "2022-10-24",
            "fechaEjecucion": "2022-10-24",
            "listaModulos": [
                {
                    "codigoModulo": "ARS027773588877",
                    "tiempoConectividad": 7964,
                    "estado": 1,
                    "porcentajeAvance": 100,
                    "fechaInicio": "2022-07-28",
                    "fechaFin": "2022-10-24",
                    "listaActividades": [
                        {
                            "codigoActividad": "Excel"
                        },
                        {
                            "codigoActividad": "Video interactivo de introducción a Excel"
                        }
                    ]
                }
            ]
        }
    ]
}

问题修复与实现方案

1. 修复GetRoot方法的核心问题

  • 循环内提前关闭数据库连接,导致第一次迭代后连接中断,直接移除手动关闭连接的代码(using块会自动管理连接生命周期)。
  • 调用GetAlumnos时传入当前课程的codigoOferta,将返回的学生列表赋值给root.listaAlumnos,实现第一层嵌套。

修改后的GetRoot:

public List<Root> GetRoot()
{
    List<Root> roots = new List<Root>();
    using (var conexion = ObtenerConexion())
    {
        conexion.Open();
        var query = @"SELECT id AS Id, fullname AS NombreCurso,  MID(fullname, INSTR(fullname, ""RLAB""), 20) AS codigoOferta
                        FROM mo_course 
                        WHERE  MID(fullname, INSTR(fullname, ""RLAB""), 20) != '';";
        var resultado = conexion.Query<Root>(query);
        
        foreach (var item in resultado)
        {
            Root root = new Root();
            root.codigoOferta = item.codigoOferta;
            // 关联当前课程的学生列表
            root.listaAlumnos = GetAlumnos(item.codigoOferta);
            roots.Add(root);
        }
    }
    return roots;
}

2. 让GetAlumnos的参数生效

  • SQL查询添加WHERE条件,通过参数化查询过滤指定codigoOferta的学生,同时修复LENGTH函数的语法错误(LENGTH(mo_user.idnumber - 2)改为LENGTH(mo_user.idnumber) - 2)。
  • 方法内创建局部的学生列表,避免全局变量导致的数据混乱。

修改后的GetAlumnos:

public List<ListaAlumno> GetAlumnos(string codigoOferta)
{
    List<ListaAlumno> listaAlumnos = new List<ListaAlumno>();
    using (var conexion = ObtenerConexion())
    {
        conexion.Open();
        // 添加参数化WHERE条件,防止SQL注入
        var query = @"SELECT mo_role_assignments.userid AS Id, firstname AS Nombre, lastname AS Apellido, 
                        LEFT(mo_user.idnumber, LENGTH(mo_user.idnumber) - 2) AS rutAlumno,
                        RIGHT(mo_user.idnumber, 1) AS dvAlumno, email AS Correo, mo_course.fullname AS NombreCurso, 
                        mo_course.idnumber AS codigoOferta,
                        FROM_UNIXTIME(startdate) AS fechaInicio, FROM_UNIXTIME(enddate) AS fechaFin
                        FROM mo_course
                        INNER JOIN mo_context ON mo_context.instanceid = mo_course.id
                        INNER JOIN mo_role_assignments ON mo_context.id = mo_role_assignments.contextid
                        INNER JOIN mo_user ON mo_role_assignments.userid = mo_user.id
                        WHERE mo_course.idnumber = @CodigoOferta;";

        // 传入参数执行查询
        var resultado = conexion.Query<ListaAlumno>(query, new { CodigoOferta = codigoOferta });
        foreach (var item in resultado)
        {
            ListaAlumno alumno = new ListaAlumno();
            alumno.codigoOferta = item.codigoOferta;
            alumno.rutAlumno = item.rutAlumno;
            alumno.dvAlumno = item.dvAlumno;
            alumno.tiempoConectividad = 0;
            alumno.estado = 0;
            alumno.porcentajeAvance = 0;
            alumno.fechaInicio = item.fechaInicio;
            alumno.fechaFin = item.fechaFin;
            alumno.fechaEjecucion = "";
            alumno.listaModulos = new List<ListaModulo>();
            // 若需要嵌套模块数据,可在此调用GetModulos方法并传入对应参数
            // alumno.listaModulos = GetModulos(item.Id, codigoOferta);
            listaAlumnos.Add(alumno);
        }
    }
    return listaAlumnos;
}

3. 生成最终嵌套JSON

确保Root类包含期望JSON的所有字段(rutOtec、idSistema、token等),使用Newtonsoft.Json或System.Text.Json序列化:

// 补充Root类的固定字段值
var rootData = GetRoot().First(); // 若有多个课程,可遍历处理
rootData.rutOtec = "9999999-9";
rootData.idSistema = 1350;
rootData.token = "AAAAAA-ASSS-DDDDd-8FFF-2FFFFFFFFD2";
rootData.codigoGrupo = rootData.codigoOferta;
rootData.codigoEnvio = rootData.codigoOferta;

// 序列化生成格式化后的JSON
string json = JsonConvert.SerializeObject(rootData, Formatting.Indented);

内容的提问来源于stack exchange,提问作者Sebastián Rivera

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 17:30:11