我有一个存储过程可以返回正确的列数,但下面的代码大部分时间都有效,但 RANDOMLY 会抛出异常。我们最近升级到.NET 4.6,之后我们注意到了异常。
问题:
1异常发生的地点和原因在哪里?
2根据底部的源代码,SQL客户端如何从服务器端接收空元数据?
存储过程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));
}
}
答案 0 :(得分:0)
缺少模式名称可能是混乱的。和你在一起。
另外,下面的C#代码中的一些调试技巧。
提供存储过程的模式名称。
IF EXISTS (
SELECT * FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'GetUser'
)
BEGIN
DROP PROCEDURE [dbo].[GetUser]
END
GO
CREATE PROCEDURE dbo.GetUser()
AS
SELECT TOP 1
FirstName, LastName
FROM
User
--omitted WHERE userid = @id
GO
将您的c#更改为:
using (var cn = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "dbo.GetUser";
cmd.Connection = cn;
cn.Open();
using (IDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
string temp = string.Empty;
int fc = dr.FieldCount;
if (fc>0)
{
object val2 = dr[0];
temp = val1.GetType().ToString();
}
if (fc>1)
{
object val2 = dr[1];
temp = val2.GetType().ToString();
}
temp = "did I get here?";
string firstName = (string)dr[0];
string lastName = (string)dr[1];
return firstName + " " + lastName;
}
}
}
答案 1 :(得分:0)
我认为这一行会让你陷入困境:
A.Value2 Ad LastName
应该是: A.Value2作为LastName
答案 2 :(得分:0)
您尚未在C#代码中指定参数userid
,请使用CommandParameter
然后尝试
答案 3 :(得分:0)
试一试 可能无法修复,但你会获得信息,至少它会优雅地失败
try
{
cn.Open();
string firstName = "not";
string lastName = "found";
using (SQLDataReader dr = cmd.ExecuteReader(CommandBehavior.SingleResult))
{
if (dr.Read()) //if there is a row, there are two columns. Thus index is used below
{
Debug.WriteLine(dr.FieldCount);
firstName = rdr.IsDBNull(0) ? string.Empty : rdr.GetString(0);
lastName = rdr.IsDBNull(1) ? string.Empty : rdr.GetString(1);
}
}
}
catch (SqlException ex)
{
Debug.WriteLine("GetUser " + Environment.NewLine + ex.Message);
}
catch (Exception ex)
{
Debug.WriteLine("GetUser" + Environment.NewLine + ex.Message);
throw ex;
}
finally
{
cn.Close();
}
return firstName + " " + lastName;