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

如何在C#中获取Oracle的JSON_OBJECT查询结果?

问题分析与解决方案

一、Oracle JSON_OBJECT实现的正确性与效率优化

你当前的SQL用JSON_OBJECT生成每行单个JSON对象,最终返回的是多行独立JSON,而非完整的JSON数组。如果要直接获取单个JSON数组结果,建议改用JSON_ARRAYAGG包裹JSON_OBJECT,让数据库直接输出完整数组,省去客户端拼接逻辑,效率更高:

SELECT JSON_ARRAYAGG(
    JSON_OBJECT(
        'uniqueId' VALUE REQUEST_ID,
        'ip' VALUE COMPUTER_EQUIPMENT_NAME,
        'lclDtm' VALUE REQ_TS,
        'utcDtm' VALUE UTC_TS,
        'errorCode' VALUE RESPONSE_ERROR_CODE
        FORMAT JSON
    )
) AS JSON_STRING
FROM(
    SELECT req.REQUEST_ID,  
           to_char(req.REQUEST_TS, 'YYYY-MM-DD"T"HH24:MI:SS.FF3') AS REQ_TS, 
           to_char(SYS_EXTRACT_UTC(CAST(req.REQUEST_TS AS TIMESTAMP)), 'YYYY-MM-DD"T"HH24:MI:SS.FF3') AS UTC_TS, 
           resp.RESPONSE_ERROR_CODE, 
           req.COMPUTER_EQUIPMENT_NAME
    FROM TBL_REQUEST req 
    INNER JOIN TBL_RESPONSE resp ON req.REQUEST_ID = resp.REQUEST_ID 
    -- 补充日期过滤条件,匹配你的参数
    WHERE req.REQUEST_TS BETWEEN TO_DATE(:StartDate, 'MM/DD/YYYY') AND TO_DATE(:EndDate, 'MM/DD/YYYY')
);

原方案需要客户端将多行JSON拼接成数组,优化后数据库直接返回完整结构,更贴合你的需求,也减少客户端处理成本。

二、C#读取数据失败(oraReader.Read()返回false)的修复

你的代码存在三个关键问题:

  1. SQL未绑定参数占位符:代码添加了StartDate和EndDate参数,但原始SQL中没有对应的:StartDate、:EndDate占位符,导致查询无结果返回。
  2. 异常被静默吞掉:ExecuteReaderCmd中捕获异常但未做任何处理,查询报错时无法排查问题(比如参数不匹配、权限不足)。
  3. DataReader生命周期异常:OracleCommand被using包裹,方法执行完毕后Command被释放,依赖其存活的DataReader直接失效。

修复后的代码示例

第一步:修正SQL(添加参数占位符)

见上方优化后的SQL语句。

第二步:修复C#读取逻辑

try
{
    dbContext.Open();
    var spParams = new List<OracleParameter>();
    spParams.Add(new OracleParameter("StartDate", OracleDbType.Varchar2, dtStartDate.ToString("MM/dd/yyyy"), ParameterDirection.Input));
    spParams.Add(new OracleParameter("EndDate", OracleDbType.Varchar2, dtEndDate.ToString("MM/dd/yyyy"), ParameterDirection.Input));
    
    string sErrors = string.Empty;
    // 使用using自动释放DataReader,同时关联连接关闭
    using (var oraReader = dbContext.ExecuteReaderCmd(sQuery, spParams))
    {
        if (oraReader.Read())
        {
            var jsonOrdinal = oraReader.GetOrdinal("JSON_STRING");
            if (!oraReader.IsDBNull(jsonOrdinal))
                sErrors = oraReader.GetString(jsonOrdinal);
        }
    }
    // 后续处理JSON字符串
}
catch (Exception ex)
{
    // 必须处理异常,比如写入日志
    Console.WriteLine($"读取数据失败:{ex.Message}");
}
finally
{
    dbContext.Close();
}

// 修改ExecuteReaderCmd方法,避免静默吞异常,调整DataReader生命周期
public OracleDataReader ExecuteReaderCmd(string sQuery, List<OracleParameter> spParams)
{
    var command = new OracleCommand()
    {
        CommandType = CommandType.Text,
        Connection = DbConnection,
        CommandText = sQuery,
        BindByName = true
    };

    if (spParams != null && spParams.Count > 0)
        command.Parameters.AddRange(spParams.ToArray());

    try
    {
        // 使用CommandBehavior.CloseConnection,关闭DataReader时自动关闭连接
        return command.ExecuteReader(CommandBehavior.CloseConnection);
    }
    catch (OracleException oex)
    {
        throw new Exception($"Oracle数据库错误:{oex.Message}", oex);
    }
    catch (Exception ex)
    {
        throw new Exception($"执行查询失败:{ex.Message}", ex);
    }
}

三、OracleDataAdapter vs OracleDataReader的选择

  • OracleDataAdapter.Fill:适合填充DataSet/DataTable,方便后续离线操作数据或映射实体类。如果用这个方式读取JSON,确保SQL和参数绑定正确,不会返回空表。示例代码:
using (var adapter = new OracleDataAdapter(sQuery, dbContext.DbConnection))
{
    adapter.SelectCommand.Parameters.AddRange(spParams.ToArray());
    adapter.SelectCommand.BindByName = true;
    var ds = new DataSet();
    adapter.Fill(ds);
    if (ds.Tables[0].Rows.Count > 0)
    {
        sErrors = ds.Tables[0].Rows[0]["JSON_STRING"].ToString();
    }
}
  • OracleDataReader:流式读取,内存占用低,适合直接读取单行/少量数据(比如你只需要一个JSON数组字符串),效率更高,是当前场景的更优选择。

内容的提问来源于stack exchange,提问作者NoBullMan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:15:06