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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:54:54