Возвращает ли ExecuteScalar сразу после SELECT?

Недавно я заметил интересное поведение.

Когда хранимая процедура MS SQL выполнялась с использованием SqlCommand.ExecuteScalar(), мое приложение, похоже, совершенно не знает о каких-либо ошибках SQL или PRINT, которые появляются после выполнения SELECT.

Наиболее вероятным объяснением является то, что управление потоком передается C# сразу после появления любого результата SELECT, не дожидаясь завершения хранимой процедуры (хотя хранимая процедура продолжает выполнение молча внизу).

Очевидным преимуществом является прирост производительности (не нужно ждать, так как результат уже известен), к сожалению, приложение C # не знает о каких-либо исключениях SQL, которые могут произойти после этого момента.

Кто-нибудь может подтвердить мое объяснение? Можно ли изменить это поведение?


person gszegosz.zojka    schedule 07.03.2013    source источник
comment
Это может ответить на ваш вопрос: stackoverflow.com/questions/7024109/, и это также может быть полезно: support.microsoft.com/kb/321903/en-us   -  person Tim Schmelter    schedule 07.03.2013
comment
Это происходит с DataReaders, если вы не читаете результат до конца потока. Не знаю навскидку, относится ли это к ExecuteScalar.   -  person Martin Smith    schedule 07.03.2013


Ответы (1)


Метод ExecuteNonQuery вызовет «ExecuteReader» и немедленно вызовет «Close» для возвращенного объекта чтения. ExecuteScalar вызовет «Чтение» один раз, выберет первое значение (индекс 0), а затем вызовет «Закрыть».

Поскольку DataReader, по сути, является не чем иным, как специализированным сетевым потоком, любая информация, которая возвращается после его текущего местоположения (при вызове Close), просто никогда не достигнет фактических клиентских компонентов, даже если сервер может Отправь это. Реализация как таковая позволяет избежать возврата огромного количества данных, когда они не требуются.

В вашем случае я вижу два решения этой проблемы.

  1. убедитесь, что вместо этого вы используете ExecuteReader, и полностью прочитайте результат:

    using(var reader = command.ExecuteReader())
    {
        do 
        {
              while (reader.Read()) { /* whatever */ };
        } while (reader.NextResult());
    }
    
  2. Если вы можете контролировать серверную часть, это поможет переместить фактический выбор «отправить клиенту» в конец рассматриваемой процедуры или пакета. Так:

    create proc Demo
    as
    declare @result int
    select top 1 @result = Id from MyTable where Name = 'testing'
    print 'selected result...'
    select @result Id  -- will send a column called "Id" with the previous value
    go
    
person Roman Gruber    schedule 12.03.2013