SqlCommand.ExecuteReaderAsync прекращает запуск события InfoMessage после первого оператора SELECT в хранимой процедуре - PullRequest
0 голосов
/ 10 мая 2019

Мне нужно использовать хранимые процедуры для доступа к данным, а также принимать сообщения (например, PRINT 'hello'), отправленные из механизма БД.

Когда я использую InfoMessage событие соединения SQL и заполняю данные вDataTable, все работает отлично.

Однако, когда мне приходится читать данные последовательно и использовать SqlDataReader.ExecuteReaderAsync, соединение прекращает запуск InfoMessage после первого оператора select в хранимой процедуре:

C # code:

using (SqlConnection con = new SqlConnection("connection-string"))
{
    con.Open();
    con.InfoMessage += (s, e) => {
        Console.WriteLine(e.Message);
    };

    using (SqlCommand command = new SqlCommand("spTestMessage", con))
    {
        command.CommandType = System.Data.CommandType.StoredProcedure;

        SqlDataReader reader = await command.ExecuteReaderAsync();

        int cntr = 0;

        while (reader.Read())
        {
            Console.WriteLine($"Loaded row {cntr++}");
        }

        // reader.NextResult(); // this line forces firing rest of InfoMessage events
    }
}

Хранимая процедура SQL:

CREATE PROCEDURE [dbo].[spTestMessage]
AS

PRINT 'Before select 1'
select * from MyTable
PRINT 'After select 1'

PRINT 'Before select 2'
select * from MyTable
PRINT 'After select 2'

Вывод программы:

Before select 1

Почему он перестает работать?Я думаю, что с Reader что-то не так, потому что когда я использую command.ExecuteNonQueryAsync(); вместо command.ExecuteReaderAsync();, он тоже работает.

Я случайно обнаружил, что строка комментария reader.NextResult(); заставляет соединение сбрасывать сообщенияи уволить оставшиеся события.Однако, это очень неудачный обходной путь.

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 13 мая 2019

Причина, по которой ваш command.ExecuteNonQueryAsync() перестает выдавать ваш результат после первого запуска, с reader.ReadAsync() или без него, потому что любая асинхронная команда SQL будет выполнена, как только первый результат будет возвращен клиенту, и info messages считается как результат. И когда вы запускаете reader.NextResult() or await reader.NextResultAsync(), он проверяет читателя на дальнейшие результаты.

Если вы хотите узнать больше о Asynchronous обработке SQL, вы можете проверить Remus answer и NextResult проверить этот пример .

Потребление InfoMessages:

var _msgs = new List<string>();
using (System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(<YourConnectionString>))
{
    //Appending an event handler for InfoMessages
    con.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs args)
    {
        //reader will invoke the delegate on every itteration of results coming from query
        _msgs.Add(args.Message);
        return;
    };
    using (var cmd = new System.Data.SqlClient.SqlCommand("spTestMessage", con))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        con.Open();
        using (System.Data.SqlClient.SqlDataReader reader = await cmd.ExecuteReaderAsync())
        {
            var incr = 0;
            while (await reader.ReadAsync())
            {
                //Statements to read data from Table1
                Console.WriteLine(reader.GetString(0));
                incr++;
            }
            while (await reader.NextResultAsync())
            {
                while (await reader.ReadAsync())
                {
                     //Statements to read data from Table2
                     Console.WriteLine(reader.GetString(0));
                     incr++;
                 }
             }
         }
     } 
}

Примечание: Приведенную выше процедуру можно использовать с операциями Synchronous, а также просто изменить сигнатуру методов с асинхронной на синхронизацию.

...