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
相关产品推荐
相关产品推荐

