2

SQL Server Management Studio で次のステートメントを実行すると

exec sp_executesql N'select 1 where 1 = @p1',N'@p1 nvarchar(3)',@p1=N'a'

行く

以下のエラーが表示されます

メッセージ 245、レベル 16、状態 1、行 1

nvarchar 値 'a' をデータ型 int に変換するときに変換に失敗しました。

しかし、ExecuteReader を使用すると、例外は発生しません。

なんで?

このエラーをアプリの例外として取得して処理するにはどうすればよいですか

System.Data.SqlClient をインポートします

モジュール Module1

Sub Main()

    Dim TestSqlConnection As SqlConnection = Nothing

    Dim TestSqlCommand As SqlCommand = Nothing

    Dim TestReader As SqlDataReader = Nothing

    Dim TestGetSchemaTable As DataTable = Nothing

    TestSqlConnection = New SqlConnection
    TestSqlConnection.ConnectionString = "Data Source=(local);Database=master;Integrated Security=true"
    TestSqlConnection.Open()
    TestSqlCommand = New SqlCommand()
    TestSqlCommand.Connection = TestSqlConnection
    TestSqlCommand.CommandType = CommandType.Text
    TestSqlCommand.CommandText = "select 1 where 1 = @p1"

    Dim TestSqlParameter As SqlParameter = New SqlParameter
    TestSqlParameter.ParameterName = "@p1"
    TestSqlParameter.SqlDbType = SqlDbType.NVarChar
    TestSqlParameter.Size = 3
    TestSqlParameter.Direction = ParameterDirection.Input
    TestSqlParameter.Value = "a"
    TestSqlCommand.Parameters.Add(TestSqlParameter)

    Try
        TestReader = TestSqlCommand.ExecuteReader()
    Catch ex As Exception
        Console.WriteLine("Exception")
    Finally
        Console.WriteLine("Finally")
    End Try
End Sub

エンドモジュール

4

3 に答える 3

3

ExecuteReader は実際にはクエリを実行しません。への最初の呼び出し.Read()でエラーがスローされます。

のみをキャッチしたい場合SqlExceptionは、次のことができます。

Try
    TestReader = TestSqlCommand.ExecuteReader()
    TestReader.Read()
Catch ex As SqlException
    Console.WriteLine("SQL error.")
Catch ex As Exception
    Console.WriteLine("Exception")
Finally
    Console.WriteLine("Finally")
End Try
于 2013-10-28T12:24:28.690 に答える
0

SQL文字列がEXEC sp_executesqlを使用して渡された場合、すべての結果と結果セットを確実に読み取ることでこの問題を解決しました...次のように:

  ....
        using (var conn = new SqlConnection(_connectionString))
        {
            try
            {
                conn.Open();
                using (var cmd = new SqlCommand(sql, conn))
                {
                    cmd.CommandTimeout = 0;
                    using (var rdr = cmd.ExecuteReader())
                    {


                       // TODO: Do stuff with the rdr here.



                        FlushReader(rdr);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Fatal("Exception: {0}\r\nSQL:\r\n{1}", ex.Message, sql);
                throw;
            }
            finally
            {
                conn.Close();
            }
        }
    ...


    /// <summary>
    /// Continue trying to read in case the server threw an exception.
    /// </summary>
    private static void FlushReader(IDataReader rdr)
    {
        while (rdr.Read())
        {
        }

        while (rdr.NextResult())
        {
            while (rdr.Read())
            {
            }
        }
    }

FlushReader メソッドを呼び出さなくても、アプリケーションはいかなる種類の例外もスローせずに続行します。SQL THROW ステートメントを使用しても。SQL 管理スタジオで同じ SQL を実行すると、エラーが表示されます。

お役に立てれば。

于 2014-04-23T07:30:42.520 に答える
0

私にとって、これはSSMSを修正します

exec sp_executesql N'select 1 where N''a'' = @p1',N'@p1 nvarchar(3)',@p1=N'a'

exec sp_executesql N'select 1 where N''1'' = @p1',N'@p1 nvarchar(3)',@p1=N'a'

私はルネ・リーダーに全く同意しません。
私のシステムでは、ExecuteReader で実行されます。
ExecuteReader が実際に実行されない場合、本当に悪い名前になります。
例外をスローしていないため、キャッチして例外ではないと考えましたか。
SQL プロファイラーでエラーが表示されることは知っていますが、構文エラーを導入すると、キャッチされます。

これは C# ですが、例外をスローしていません。
そして、それを次のように変更すると:
"select 1 where N'a' = @p1";
次に、行を返します。

構文エラーが発生した場合:
"select 1 whereX 1 = @p1";
次に、例外をスローし、それを ExecuteReader 行にスローします。

1 をリテラルにしたい場合は、
"select 1 where '1' = @p1"; を使用する必要があります。

SQLcmd.CommandType = CommandType.Text;
SQLcmd.CommandText = "select 1 where N'1' = @p1";
SqlParameter TestSqlParameter = new SqlParameter();
TestSqlParameter.ParameterName = "@p1";
TestSqlParameter.SqlDbType = SqlDbType.NChar;
TestSqlParameter.Value = "a";
SQLcmd.Parameters.Add(TestSqlParameter);
try
{
    rdr = SQLcmd.ExecuteReader();
    Int32 waste;
    if (rdr.HasRows)
    {
        while (rdr.Read())
        {
            waste = rdr.GetInt32(0);
        }
    }
}
catch (Exception Ex)
{
    Debug.WriteLine(Ex.Message);
}
于 2013-10-29T13:57:20.957 に答える