使用Dapper时.NET Core Web API无法获取结果集问题排查
问题分析与解决方案
针对.NET Core 7 Web API中调用Oracle存储过程返回空结果的问题,结合代码和存储过程,总结以下问题点及修复方案:
1. 存储过程存在语法错误,触发异常关闭结果游标
存储过程中拼接日志参数时,错误使用了未定义的变量iUserName,实际输入参数为iName。此错误会触发PL/SQL运行时异常,进入EXCEPTION块后执行CLOSE EMPLISTCURSOR;,导致结果游标被提前关闭,.NET端无法读取数据。
修复后的存储过程代码片段:
PROCEDURE getEmployeeList (iName IN VARCHAR2, ino IN NUMBER, iPassport IN VARCHAR2, iID IN NUMBER, iLastName IN VARCHAR2, iFirstName IN VARCHAR2, oCallStatus OUT SYS_REFCURSOR, EMPLISTCURSOR OUT SYS_REFCURSOR) IS vInputParam VARCHAR2 (4000); BEGIN vInputParam := 'iName:' || iName || ' ino:' || ino || ' iPassport:' || iPassport || ' ID:' || iID || ' iLastName:' || iLastName || ' iFirstName:' || iFirstName; --log input parameters OPEN EMPLISTCURSOR FOR SELECT empno NOM FROM employee WHERE ROWNUM < 10; OPEN oCallStatus FOR SELECT 'Y' STATUS, NULL MESSAGE, NULL ERROR_ID FROM DUAL; EXCEPTION WHEN OTHERS THEN gSqlErrorCode := SQLCODE; gSqlErrorMessage := SQLERRM; OPEN oCallStatus FOR SELECT 'N' STATUS, 'Error occured while getting employee list' MESSAGE, REPLACE (gSqlErrorCode, 'ORA', '') ERROR_ID FROM DUAL; -- 异常时无需手动关闭游标,Oracle会自动处理,避免提前关闭导致读取失败 -- CLOSE EMPLISTCURSOR; --log Error END getEmployeeList;
2. Dapper结果集读取顺序与存储过程输出参数顺序不匹配
存储过程定义的输出参数顺序为oCallStatus(先)、EMPLISTCURSOR(后),Dapper返回的结果集顺序严格遵循此参数定义顺序。但原有代码中先读取EMPLISTCURSOR对应的数据,实际读取的是oCallStatus的结果(无法映射到Employee类,返回空),再读取oCallStatus时得到的是员工数据(无法映射到CallStatus类,返回null)。
修复后的服务代码片段:
var result = await connection.QueryMultipleAsync("getEmployeeList", parameters, commandType: CommandType.StoredProcedure); // 先读取调用状态(对应第一个输出参数oCallStatus) var callStatus = await result.ReadFirstOrDefaultAsync<CallStatus>().ConfigureAwait(false); // 再读取员工列表(对应第二个输出参数EMPLISTCURSOR) var emps = await result.ReadAsync<Employee>().ConfigureAwait(false); var emplist = emps.ToList(); //Log the values _logger.LogInformation($"emps: {emplist.LongCount()}"); _logger.LogInformation($"Call status: {callStatus?.Status}, message: {callStatus?.Message}, ErrorID: {callStatus?.ErrorID}"); return (emplist, callStatus);
3. 输入参数类型不匹配,导致查询条件失效
.NET代码中输入参数使用OracleDbType.Char,但存储过程定义的是VARCHAR2类型。Char类型会自动填充空格,可能导致传入的参数值与数据库中的数据不匹配(比如"张三"变成"张三 "),从而没有符合条件的结果返回。
修复后的参数添加代码:
//Input Parameters parameters.Add("iName", OracleDbType.Varchar2, ParameterDirection.Input, inputParameters.UserName); parameters.Add("ino", OracleDbType.Int32, ParameterDirection.Input, inputParameters.no); parameters.Add("iPassport", OracleDbType.Varchar2, ParameterDirection.Input, inputParameters.Passport); parameters.Add("iID", OracleDbType.Int32, ParameterDirection.Input, inputParameters.LOEID); parameters.Add("iLastName", OracleDbType.Varchar2, ParameterDirection.Input, inputParameters.LastName); parameters.Add("iFirstName", OracleDbType.Varchar2, ParameterDirection.Input, inputParameters.FirstName);
4. 确认CallStatus类属性映射正确
确保CallStatus类的属性名与存储过程返回的列名一致(Oracle列名默认大写,Dapper支持大小写不敏感,但建议显式匹配):
public class CallStatus { public string? Status { get; set; } public string? Message { get; set; } public string? ErrorID { get; set; } // 对应存储过程中的ERROR_ID列 }
内容的提问来源于stack exchange,提问作者Shivdutt
相关产品推荐
相关产品推荐

