【发布时间】:2016-12-08 09:15:50
【问题描述】:
我有一个返回正确列数的存储过程,但下面的代码大部分时间都有效,但 RANDOMLY 在下面抛出异常。我们最近升级到 .NET 4.6,之后我们注意到异常。
问题:
1 异常发生的位置和原因?
2 根据底部的源码,SQL客户端怎么可能从服务器端接收到空的metaData?
存储过程GetUser:
CREATE PROCEDURE [dbo].[GetUser]
@UserID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @UserIDChar NVARCHAR(255);
SET @UserIDChar = convert(nvarchar(255), @UserID);
SELECT TOP 1
A.Value1 As FirstName,
A.Value2 As LastName
-- three more columns omitted here
FROM dbo.Activity as A
WHERE A.ActivityValue = @UserIDChar --ActivityValue is NVARCHAR(255) type
ORDER BY A.DateCreated DESC
SET NOCOUNT OFF;
END
C#网络层:
using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetUser"; //the proc returns one row that consists of two columns
cmd.Connection = cn;
cmd.Parameters.AddWithValue("@UserID", userId);
cn.Open();
using (IDataReader dr = cmd.ExecuteReader(CommandBehavior.SingleResult))
{
if (dr.Read()) //check if row is available
{
string firstName = (string)dr[0];
string lastName = (string)dr[1];
// three more columns omitted here
return firstName + " " + lastName;
}
}
}
错误:
异常类型:System.IndexOutOfRangeException
消息:索引超出了数组的范围。
数据:System.Collections.ListDictionaryInternal
TargetSite: Void CheckDataIsReady(Int32, Boolean, Boolean, System.String)
来源:System.Data
源码如下:
private void CheckDataIsReady(int columnIndex, bool allowPartiallyReadColumn = false, bool permitAsync = false, string methodName = null) {
if (_isClosed) {
throw ADP.DataReaderClosed(methodName ?? "CheckDataIsReady");
}
if ((!permitAsync) && (_currentTask != null)) {
throw ADP.AsyncOperationPending();
}
Debug.Assert(!_sharedState._dataReady || _metaData != null, "Data is ready, but there is no metadata?");
if ((!_sharedState._dataReady) || (_metaData == null)) {
throw SQL.InvalidRead();
}
if ((columnIndex < 0) || (columnIndex >= _metaData.Length)) {
throw ADP.IndexOutOfRange();
}
if ((IsCommandBehavior(CommandBehavior.SequentialAccess)) && // Only for sequential access
((_sharedState._nextColumnDataToRead > columnIndex) || (_lastColumnWithDataChunkRead > columnIndex) || // Read past column
((!allowPartiallyReadColumn) && (_lastColumnWithDataChunkRead == columnIndex)) || // Partially read column
((allowPartiallyReadColumn) && (HasActiveStreamOrTextReaderOnColumn(columnIndex))))) { // Has a Stream or TextReader on a partially-read column
throw ADP.NonSequentialColumnAccess(columnIndex, Math.Max(_sharedState._nextColumnDataToRead, _lastColumnWithDataChunkRead + 1));
}
}
【问题讨论】:
-
TOP没有明确的ORDER BY是没有意义的 - 你希望得到哪个TOP 1行?如果没有明确的排序,它是任意的——你只会从你的表中取回一个或多或少随机选择的行...... -
您的存储过程中可能需要
SET NOCOUNT ON。可能发生的情况是返回的记录数而不是SELECT的结果。 -
@Kendo -
dr.Read()在那种情况下不会返回 false。 -
请为
GetUser发布您实际完整的存储过程脚本;您的C#代码看起来不错 -
我相信你最后不需要
SET NOCOUNT OFF。
标签: c# asp.net .net sql-server tsql