使用ADO.NET获取带FOR JSON AUTO的存储过程数据时遇索引越界异常
问题原因
当存储过程使用FOR JSON AUTO时,SQL Server不会返回常规的多列行集,而是返回单个值的结果集(即完整的JSON字符串),默认列名是JSON_F52E2B61-18A1-11d1-B105-00805F49916B,而非你原本定义的Id、用户名等列。这就是为什么SqlDataReader找不到Id列——结果集里根本不存在这个列。
解决方法
根据你的需求,有两种处理方式:
方式1:读取JSON字符串并反序列化
如果确实需要返回JSON格式数据,修改C#代码读取返回的JSON字符串,再反序列化为对象:
using (var connection = new SqlConnection("你的连接字符串")) { var command = new SqlCommand("Login", connection); command.CommandType = CommandType.StoredProcedure; // 添加存储过程参数(如果有) // command.Parameters.AddWithValue("@Username", username); connection.Open(); using (var reader = command.ExecuteReader()) { if (reader.Read()) { // 读取JSON字符串(用索引0或指定别名) string userJson = reader.GetString(0); // 反序列化为用户对象(以System.Text.Json为例) var user = System.Text.Json.JsonSerializer.Deserialize<User>(userJson); // 后续使用user.Id、user.Username等属性 } } }
同时可以修改存储过程,给JSON列加别名,让代码更易读:
CREATE PROCEDURE Login @Username NVARCHAR(50), @Password NVARCHAR(50) AS BEGIN SELECT ( SELECT Id, Username, Email FROM Users WHERE Username = @Username AND Password = @Password FOR JSON AUTO ) AS UserJson; END
此时C#里可以用reader["UserJson"]替代索引0读取:
string userJson = reader["UserJson"].ToString();
方式2:保留常规行集输出
如果不需要JSON格式,直接移除FOR JSON AUTO语句即可;如果需要同时支持两种输出格式,可以给存储过程加参数控制:
CREATE PROCEDURE Login @Username NVARCHAR(50), @Password NVARCHAR(50), @ReturnJson BIT = 0 AS BEGIN IF @ReturnJson = 1 SELECT Id, Username, Email FROM Users WHERE Username = @Username AND Password = @Password FOR JSON AUTO; ELSE SELECT Id, Username, Email FROM Users WHERE Username = @Username AND Password = @Password; END
在C#里根据业务需求传入@ReturnJson参数,选择对应的读取方式:如果参数为0,就可以像之前一样直接读取Id等列。
额外排查点
检查存储过程是否包含多个SELECT语句或PRINT语句,导致返回多个结果集。如果有,需要用reader.NextResult()切换到正确的结果集后再读取数据。
内容的提问来源于stack exchange,提问作者MaryBhatta
相关产品推荐
相关产品推荐

