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

如何在C#中完整获取SQL存储过程返回的超长JSON结果

解决SAP B1 Recordset读取超长JSON被截断的问题

问题场景

调用SQL存储过程返回超长JSON时,C#端通过SAPbobsCOM.Recordset读取结果,JSON在255字节处被截断。直接在SQL执行存储过程可得到完整结果,问题出在C#的结果读取环节。

现有C#代码:

var selectQuery = $"exec [dbo].[GetOrderStatus] '{order}' ";

SAPbobsCOM.Recordset ss = SAPConnection.GetInstance().Recordset;
ss.DoQuery(selectQuery);
if (ss.EoF) { return new ResponseData() { Status = StatusE.GanericError, ErrorMessage = $"Error in exec proc, {selectQuery}" }; }
dynamic jsonResult = (ss.Fields.Item(0).Value);
if (!string.IsNullOrEmpty(jsonResult))
{
    return new ResponseData() { Status = StatusE.succsed, ErrorMessage = "", ValueResult = jsonResult };
}

对应的SQL存储过程:

ALTER PROCEDURE [dbo].[GetOrderStatus]
@SiteRdr as nvarchar(50)
AS
BEGIN
declare @Output nvarchar(max)
set @Output=(
        SELECT
                    (SELECT DISTINCT
                        o.DocEntry AS SapEntry,
                        o.DocNum as DocNum,
                        o.U_SiteRdr as SiteEntry,
                        o.DocStatus AS [Status],
                        o.CreateDate as CreateDate,
                        o.U_DeliveryNo as DeliveryNo,
                        o.U_Site as SiteName,
                        o.DocTotal,
                        (
                            SELECT
                                o1.ItemCode,
                                s.U_SiteID,
                                o1.Quantity,
                                o1.Factor1,
                                o1.U_Flavor as flavor,
                              o1.LineTotal,
                                o1.CodeBars as Barcode
                            FROM rdr1 o1 join [@SITECODE]s on o1.ItemCode=s.U_ItemCode
                            WHERE o.DocEntry = o1.DocEntry
                            FOR JSON AUTO, ROOT('Items')
                        ) AS OrderItems
                    
                    FROM
                        ordr o
                    WHERE
                        o.U_siterdr = @SiteRdr
                    FOR JSON AUTO, ROOT('Order')
                    )As [Order]
        
                    ,(SELECT DISTINCT
                        o.DocEntry AS SapEntry,
                        o.DocNum as DocNum,
                        o.U_SiteRdr as SiteEntry,
                        o.DocStatus AS [Status],
                        o.CreateDate as CreateDate,
                        o.U_DeliveryNo as DeliveryNo,
                        o.U_Site as SiteName,
                        o.U_Address as [Address],
                        o.u_city as city,
                     o.DocTotal,
                        (
                            SELECT
                                o1.ItemCode,
                                s.U_SiteID,
                                o1.Quantity,
                                o1.LineTotal,
                                o1.CodeBars as Barcode,
                                o1.U_BCCheck as BCCheck,
                                o1.U_QtyCheck as QtyCheck
                            FROM dln1 o1 join [@SITECODE]s on o1.ItemCode=s.U_ItemCode
                            WHERE o.DocEntry = o1.DocEntry
                            FOR JSON AUTO, ROOT('Items')
                        ) AS DeliveryItems
                    
                    FROM
                        odln o
                    WHERE
                        o.U_siterdr = @SiteRdr
                    FOR JSON AUTO, ROOT('DeliveryNote')
                    )As [DeliveryNote]
                        ,(SELECT DISTINCT
                        o.DocEntry AS SapEntry,
                        o.DocNum as DocNum,
                        o.U_SiteRdr as SiteEntry,
                        o.DocStatus AS [Status],
                        o.CreateDate as CreateDate,
                        o.U_DeliveryNo as DeliveryNo,
                        o.U_Site as SiteName,
                        o.U_Address as [Address],
                        o.u_city as city,
                      o.DocTotal,
                        (
                            SELECT
                                o1.ItemCode,
                                s.U_SiteID,
                                o1.Quantity,
                                o1.LineTotal,
                                o1.CodeBars as Barcode
                            FROM RDN1 o1 join [@SITECODE]s on o1.ItemCode=s.U_ItemCode
                            WHERE o.DocEntry = o1.DocEntry
                            FOR JSON AUTO, ROOT('Items')
                        ) AS ReturnCertificateItems
                    
                    FROM
                        ORDN o
                    WHERE
                        o.U_siterdr = @SiteRdr
                    FOR JSON AUTO, ROOT('ReturnCertificate')
                    )As [ReturnCertificate]
        from ordr 
        join rdr1 on ordr.docentry=rdr1.docentry
        left join dln1 on rdr1.DocEntry=dln1.BaseEntry
        left join rdn1 on dln1.DocEntry=rdn1.BaseEntry
        where ordr.U_SiteRdr=@SiteRdr
        
        FOR JSON AUTO, ROOT('OrderDetails')
        )
        select @Output
END

解决方案

1. 使用GetString方法读取完整字段值

SAPbobsCOM.Recordset的Fields.Item(0).Value默认会将长文本截断为255字符,改用GetString方法可以读取完整内容:

var selectQuery = $"exec [dbo].[GetOrderStatus] '{order}' ";

SAPbobsCOM.Recordset ss = SAPConnection.GetInstance().Recordset;
ss.DoQuery(selectQuery);
if (ss.EoF) { return new ResponseData() { Status = StatusE.GanericError, ErrorMessage = $"Error in exec proc, {selectQuery}" }; }

// 读取完整字段内容
string jsonResult = ss.Fields.Item(0).GetString(0, (int)ss.Fields.Item(0).ActualSize);

if (!string.IsNullOrEmpty(jsonResult))
{
    return new ResponseData() { Status = StatusE.succsed, ErrorMessage = "", ValueResult = jsonResult };
}

GetString参数说明:第一个参数是读取起始位置(从0开始),第二个参数是读取的字节数,通过ActualSize获取字段实际长度,确保读取全部内容。

2. 验证存储过程返回字段类型(可选)

虽然存储过程中@Output是nvarchar(max),但可以在最后显式指定返回类型,避免隐式转换:

select CAST(@Output as nvarchar(max)) as OutputJSON

这一步作为兜底验证,确保SQL返回的是最大长度的文本类型。

3. 修复动态SQL注入风险(建议)

当前代码通过字符串拼接生成执行语句,存在SQL注入风险,建议改用参数化调用:

SAPbobsCOM.Recordset ss = SAPConnection.GetInstance().Recordset;
// 使用参数化方式传递参数
ss.Parameters.Add("@SiteRdr", SAPbobsCOM.BoFieldTypes.db_NVarChar, 50);
ss.Parameters.Item("@SiteRdr").Value = order;
ss.DoQuery("exec [dbo].[GetOrderStatus] @SiteRdr");

if (ss.EoF) { return new ResponseData() { Status = StatusE.GanericError, ErrorMessage = $"Error in exec proc" }; }

string jsonResult = ss.Fields.Item(0).GetString(0, (int)ss.Fields.Item(0).ActualSize);
if (!string.IsNullOrEmpty(jsonResult))
{
    return new ResponseData() { Status = StatusE.succsed, ErrorMessage = "", ValueResult = jsonResult };
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 00:57:06