Подтвердить что ты не робот

Есть ли ошибка в SqlDataReader.HasRows при работе с SQL Server 2008?

Взгляните на эти два вопроса:

-- #1
SELECT * FROM my_table
WHERE CONTAINS(my_column, 'monkey')

-- #2
SELECT * FROM my_table
WHERE CONTAINS(my_column, 'a OR monkey')  -- "a" is a noise word

ЗапроС# 1 возвращает 20 строк, когда я запускаю его в Management Studio.
Запрос № 2 возвращает те же 20 строк, но я также вижу на вкладке "Сообщения" следующее:

Информационное: условие полнотекстового поиска содержит слово шума.

До сих пор так скучно - именно то, что я ожидал бы.

Теперь посмотрим на этот фрагмент С#:

using (SqlConnection conn = new SqlConnection(...))
{
    SqlCommand cmd = conn.CreateCommand();
    // setup the command object...

    conn.Open();
    using (SqlDataReader dr = cmd.ExecuteReader())
    {
        if (dr.HasRows)
        {
            // get column ordinals etc...

            while (dr.Read())
            {
                // do something useful...
            }
        }
    }
}

Когда я запускаю этот код по запросу # 1, все ведет себя так, как ожидалось, секция "делать что-то полезное" попадает для каждой из 20 строк.

Когда я запускаю его против запроса №2, ничего не происходит - раздел "сделать что-то полезное" никогда не достигается.

Теперь, когда вещи становятся немного интереснее...

Если я удалю проверку HasRows, тогда все будет работать так, как ожидалось, секция "сделать что-то полезное" попадет для каждой из 20 строк, независимо от того, какой запрос используется.

Похоже, что свойство HasRows неправильно заполнено, если SQL Server генерирует сообщение. Результаты возвращаются и могут быть повторены с помощью метода Read(), но свойство HasRows будет ложным.

Является ли это известной ошибкой в ​​.NET и/или SQL Server, или я пропустил что-то очевидное?
Я использую VS2008SP1,.NET3.5SP1 и SQL2008.

EDIT: Я понимаю, что мой вопрос очень похож на этот, и это почти наверняка является проявлением той же проблемы, но этот вопрос увяз в течение трех месяцев без окончательного ответа.

4b9b3361

Ответ 1

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

bool readerHasRows=false;
while(reader.reader())
{
   readerHasRows=true;
   doStuffOverAndOver();
}
if (!readerHasRows)
{
   probablyBetterShowAnErrorMessageThen();
}

Что было действительно странно, так это то, что он работал на одной странице aspx, а не в другой, несмотря на то, что кодовые блоки почти идентичны используемой хранимой процедуре.

Излишне говорить, что я избегаю .HasRows с этого момента;)

EDIT. Студия Management Studio также отображает сообщения на вкладке сообщений в процедуре проблем в моем проекте. Таким образом, это, по-видимому, является причиной проблемы. Но почему это должно было случиться .HasRows??

EDIT2. Подтвержденный, изменил запрос, чтобы избежать предупреждений, а hrows теперь прав.

Ответ 2

Это, безусловно, странное поведение, но мне интересно, почему вам нужно проверить HasRows, если вы собираетесь просто перебирать результирующий набор.

Свойство HasRows инкапсулирует поле _hasRows, которое по множеству разных причин устанавливается в true или false внутри SqlDataReader во многих разных местах. В большинстве этих мест он установлен на true, если частный метод TdsParserStateObject PeekByte возвращает число, указывающее на наличие данных.

Ответ 3

Похоже, что HasRows является одним из тех свойств, значение которого не гарантируется точно...

Я согласен с предыдущими двумя сообщениями (о том, чтобы идти прямо во время (dr.Read()) и получить ординалы на первой итерации). Кроме того, почему бы не получить набор данных вместо устройства чтения данных? Если в этом случае вы имеете дело только с 20 строками, получение всего набора данных сразу может не сильно повлиять на производительность по сравнению с использованием устройства чтения данных. Я знаю, что это на самом деле не отвечает на ваш вопрос, а просто мысль об обходном пути.

Ответ 4

Как и в случае с Andrew, я не уверен, почему вы не просто используете цикл while, чтобы избежать повышения производительности дополнительных вызовов GetOrdinal. вы можете использовать значение флага для выполнения вызовов GetOrdinal в первой строке, после чего код можно пропустить.

Я заметил аналогичные проблемы с HasRows в прошлом и пошел к шаблону, подобному моему, указанному выше с минимальными проблемами.

Ответ 5

Попробуйте следующее и сообщите, было ли это успешным:

using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.SingleResult))

Ответ 6

Я бы предложил вызвать метод NextResult, если, как подозревают, возникли проблемы с несколькими наборами результатов. Поскольку первый набор результатов - тот, который кажется пустым, использование CommandBehavior.SingleResult не изменило бы поведение, так как первый (пустой) результат все равно будет возвращен. Вы могли бы попробовать это. Во всяком случае, я слышал, что это была ошибка, но я не помню, где я ее читал, и быстрый поиск в Google не дал никаких результатов.