No exception with SqlDataReader.ExecuteReader while SQL Server returns converstion error

StackOverflow https://stackoverflow.com/questions/19634521

Вопрос

When I execute the following statement in SQL Server Management Studio

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

go

I get the below error

Msg 245, Level 16, State 1, Line 1

Conversion failed when converting the nvarchar value 'a' to data type int.

But when I use ExecuteReader, I don't get any exception

Why?

How can I get and handle this error as exception in app

Imports System.Data.SqlClient

Module 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

End Module

Это было полезно?

Решение 2

For me this fixes the 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'

I totally disagree with Rene Reader.
On my system it executes on ExecuteReader.
ExecuteReader would be a real bad name if it did not actually execute.
Did you consider that it is not catching and exception because it is not throwing an exception.
I know you see an error in SQL Profiler but if I introduce a syntax error it is caught.

This is C# but is is not throwing an exception for me.
And if I change it to:
"select 1 where N'a' = @p1";
Then it returns a row.

If I introduce a syntax error:
"select 1 whereX 1 = @p1";
Then it does throw an exception and it throws it on the ExecuteReader line.

If you want 1 to be a literal you should use:
"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);
}

Другие советы

ExecuteReader doesn't actually perform the query. The first call to .Read() will throw the error.

If you want to only catch the SqlException you can do the following:

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

I solved this problem if the sql string passed used EXEC sp_executesql by ensuring I read every result and result set... like so:

  ....
        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())
            {
            }
        }
    }

Without calling the FlushReader method the application continues without throwing an exception of any kind. Even if I use a SQL THROW statement. Running the same sql in SQL management studio will show the error.

Hope this helps.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top