ASP.NET接口返回报表数据最后三字段重复 与数据库查询结果不一致
问题描述
调用自定义Ajax请求对接后端接口时,接口返回数据最后三个字段值重复。已直接在数据库执行对应查询语句校验,确认数据库返回结果和Ajax拿到的接口返回数据存在差异,各环节代码如下。
ASP.NET后端接口代码
[HttpGet] public List<Reportes> GetScrapReport(string fecha, string fechaend) { try { var fechaparametro = new SqlParameter("@fecha", fecha); var fechafinparametro = new SqlParameter("@fechafin", fechaend); var listareport = _context.Reportes.FromSqlRaw($"SELECT DISTINCT idscrap, fecha, modelo, elemento, nombre, numeroparte, cantidad FROM F_GetScrapReport (@fecha, @fechafin)", fechaparametro, fechafinparametro); return listareport.ToList(); } catch { return new List<Reportes>(); } }
Reportes实体类结构
public class Reportes { [Key] public int Idscrap { get; set; } public DateTime fecha { get; set; } public string modelo { get; set; } public string elemento { get; set; } public string? nombre { get; set; } public string? numeroparte { get; set; } public int? cantidad { get; set; } }
前端Ajax请求函数
function GetScraptime() { var j = 0; var fecha = document.getElementById('scraptime'); var fechafin = document.getElementById('scraptimetwo'); console.log(fecha.value); console.log(fechafin.value); if (fecha.value == "" || fechafin.value == "") { console.log("Uno de los parametros esta vacio"); } else { $.ajax({ method: "GET", url: "Reportes/GetScrapReport", contentType: "aplication/json; Charset=utf-8", data: { 'fecha': fecha.value, 'fechaend': fechafin.value }, async: true, success: function (result) { console.log(result.length); $("#tabletimescrap").html(''); while (j < result.length) { $("#tabletimescrap").append("<tr>"); $("#tabletimescrap").append("<td>" + result[j].idscrap + "</td>"); $("#tabletimescrap").append("<td>" + result[j].fecha + "</td>"); $("#tabletimescrap").append("<td>" + result[j].modelo + "</td>"); $("#tabletimescrap").append("<td>" + result[j].elemento + "</td>"); $("#tabletimescrap").append("<td>" + result[j].nombre + "</td>"); $("#tabletimescrap").append("<td>" + result[j].numeroparte + "</td>"); $("#tabletimescrap").append("<td>" + result[j].cantidad + "</td>"); $("#tabletimescrap").append("</tr>"); j = j + 1; } console.log(result); } }); } }
SQL自定义函数实现
CREATE FUNCTION F_GetScrapReport (@fecha varchar(20), @fechafin varchar(20)) RETURNS TABLE AS RETURN ( SELECT [Scrap].IDScrap ,[fecha] ,M.modelo ,[elemento] ,P.nombre ,P.numeroparte ,[cantidad] FROM [dbo].[Scrap] FULL OUTER JOIN Scraparte Sc ON dbo.[Scrap].IDScrap = Sc.IDScrap JOIN Modelo M ON dbo.[Scrap].IDModelo = M.IDModelo LEFT JOIN Parte P ON Sc.IDParte = P.IDParte WHERE dbo.[Scrap].fecha >= convert(varchar,REPLACE(@fecha,'"','') , 23) AND dbo.[Scrap].fecha<= DATEADD(HOUR,23.9999,convert(varchar, REPLACE(@fechafin,'"',''), 23)))
数据库验证查询语句
SELECT DISTINCT idscrap, fecha, modelo, elemento, nombre, numeroparte, cantidad FROM F_GetScrapReport('2022-07-06','2022-07-06')

异常表现
前端视图渲染结果中,nombre、numeroparte、cantidad三个列的值出现重复,和数据库查询的正确结果完全不符。
问题原因
- 核心原因:EF Core实体身份解析机制导致映射错乱
你给Reportes实体的Idscrap属性标记了[Key]主键特性,但SQL查询因为多表关联,同一个idscrap会对应多行记录(单张报废单可关联多个零件条目)。EF Core做结果映射时,遇到主键值相同的记录会判定为同一个实体,不会新建对象,后续同主键记录的字段值无法被正确映射,直接导致后三个关联字段值重复。 - 前端隐患
循环变量j定义在ajax回调外层,多次快速触发异步请求时会出现计数错乱;另外contentType存在拼写错误(写为aplication,正确为application),GET请求不需要设置该参数,虽不影响当前功能但属于不规范写法。
修复方案
后端修复
二选一即可:
- 方案1(推荐):新建无主键的DTO类接收查询结果,避免EF主键校验
public class ScrapReportDto { public int Idscrap { get; set; } public DateTime fecha { get; set; } public string modelo { get; set; } public string elemento { get; set; } public string? nombre { get; set; } public string? numeroparte { get; set; } public int? cantidad { get; set; } }
将接口返回类型改为List<ScrapReportDto>,FromSqlRaw泛型参数同步替换为ScrapReportDto即可。
- 方案2:保留原有实体,查询时加
AsNoTracking()关闭变更跟踪,绕过身份解析
var listareport = _context.Reportes .AsNoTracking() .FromSqlRaw($"SELECT DISTINCT idscrap, fecha, modelo, elemento, nombre, numeroparte, cantidad FROM F_GetScrapReport (@fecha, @fechafin)", fechaparametro, fechafinparametro);
前端修复
将循环变量移入回调内部,用for循环替代while循环避免计数异常,移除不必要的contentType配置:
success: function (result) { console.log(result.length); $("#tabletimescrap").html(''); for(let j = 0; j < result.length; j++) { $("#tabletimescrap").append(`<tr> <td>${result[j].idscrap}</td> <td>${result[j].fecha}</td> <td>${result[j].modelo}</td> <td>${result[j].elemento}</td> <td>${result[j].nombre}</td> <td>${result[j].numeroparte}</td> <td>${result[j].cantidad}</td> </tr>`); } console.log(result); }
内容的提问来源于stack exchange,提问作者Robinson
相关产品推荐
相关产品推荐

