4

介绍

我在 .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”将在结果窗格中报告错误,如下所示:

消息 512,级别 16,状态 1,过程测试,第 3 行子查询返回超过 1 个值。当子查询跟随 =、!=、<、<=、>、>= 或子查询用作表达式时,这是不允许的。

预期行为

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

提升错误

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

替代问题

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

Raiserror after

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)

这表明选择语句停止执行存储过程。

除以零

alter proc test
as
select 1/0

我的结论是 SqlClient 不能正确识别 tSql 批处理的错误状态。有没有人遇到过这个并找到了解决方案?我一直相信 .Net 框架会在任何 tSql 错误上引发异常。

4

1 回答 1

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 进行或不进行测试,然后查看效果。

于 2012-06-22T14:01:12.667 回答