4

はじめに

.Net 4.0.30319 SP1Rel の SqlClient に問題があり、ストアド プロシージャで次のエラーが発生したときに例外がスローされません。

サブクエリが複数の値を返しました。サブクエリが =、!=、<、<=、>、>= の後にある場合、またはサブクエリが式として使用されている場合、これは許可されません。

これを示す小さなプログラムとストアド プロシージャを作成しました。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();
        }
    }
}

このアプリケーションを実行すると、コンソールに「Finished」と表示されます。

SQL Server Management Studio でストアド プロシージャ 'test' を実行すると、結果ペインに次のようなエラーが報告されます。

メッセージ 512、レベル 16、状態 1、手順テスト、行 3 サブクエリが複数の値を返しました。サブクエリが =、!=、<、<=、>、>= の後にある場合、またはサブクエリが式として使用されている場合、これは許可されません。

期待される動作

次の例でストアド プロシージャを置き換えると、予想される System.Data.SqlClient.SqlException が発生します。

レイズエラー

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

代替問題

私が見つけた他のいくつかの定義も同様に例外をスローしません。

レイズエラー

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さんの親切で迅速なコメントのおかげで、この奇妙な動作の原因がわかりました。

過去に、プログラマーの 1 人が、次のように、行が存在するかどうかを確認するテストでリーダーの読み取りをラップしました。

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 に答える