tSQL错误“子查询返回多个值...”不会在SqlClient中引发异常

时间:2012-06-22 11:59:20

标签: .net tsql sqlclient

简介

我在.Net 4.0.30319 SP1Rel中的SqlClient存在问题,当我的存储过程处理以下错误时,不会抛出异常:

  

子查询返回的值超过1。当子查询遵循=,!=,<,< =,>,> =或子查询用作表达式时,不允许这样做。

我已经创建了一个小程序和存储过程来演示这个。 Sql Server版本是9.0.4053。

代码示例

存储过程

create proc test
as
select case (select 1 union select 2) when 1 then 1 else 2 end

.Net控制台应用

using System;
using System.Data;
using System.Data.SqlClient;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            SqlConnection conn = new SqlConnection("<your connection string>");
            conn.Open();

            SqlCommand cmd = new SqlCommand("test", conn);
            cmd.CommandType = CommandType.StoredProcedure;
            try
            {
                SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                Console.WriteLine("Finished");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            Console.ReadKey();
        }
    }
}

运行此应用程序只需将“完成”写入控制台。

在de SQL Server Management Studio中运行存储过程'test'将在结果窗格中报告错误,如:

  

Msg 512,Level 16,State 1,Procedure test,Line 3   子查询返回的值超过1。当子查询遵循=,!=,&lt;,&lt; =,&gt;,&gt; =或子查询用作表达式时,不允许这样做。

预期行为

通过以下示例替换存储过程将给出预期的System.Data.SqlClient.SqlException。

RAISERROR

alter proc test
as
raiserror('Not good at all!', 16, 1)

替代问题

我发现的其他一些定义也不会抛出异常。

之后的Raiserror
alter proc test
as
select case (select 1 union select 2) when 1 then 1 else 2 end
raiserror('Not good at all!', 16, 1)

这表明select语句会停止执行存储过程。

除以零

alter proc test
as
select 1/0

我的结论是SqlClient无法正确识别tSql批处理的错误状态。有没有人遇到这个并找到了解决方案?我总是信任.Net框架,在任何tSql错误上抛出异常。

1 个答案:

答案 0 :(得分:2)

感谢Martin的有用和迅速的评论,我找到了这种奇怪行为的原因。

过去,其中一位程序员在阅读器中读取读取内容以查看是否有任何行,如下所示:

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);

if (reader.HasRows)
{
    while (reader.Read()) { /* Do Something */ }
}

我不知道为什么,因为当没有行时,read()方法会在第一次调用时返回false。

无论如何,当tSQL中发生错误时,HasRows属性返回false并且从未调用过Read()方法。由于这个原因,SQL错误没有透露给SqlClient而且没有异常被抛出。

您可以将此代码段添加到示例项目中,就在ExecuteReader之后,有或没有HasRows测试,并查看效果。