Могу ли я прервать чтение данных во время чтения? - PullRequest
7 голосов
/ 25 января 2012

Можно ли остановить работающий считыватель?

Сценарий: у меня есть таблица с 100000 наборами данных

CREATE TABLE stock (
uid bigint NOT NULL,
name text,
quantity integer,
x bytea,
y bytea
);

и консольное приложение (.NET 4.0, Npgsql 2.0.11.0/ 2.0.0.92) для чтения данных

conn = new NpgsqlConnection("Server=localhost;Database=postgres;User id=postgres;password=postgres;Timeout=600;CommandTimeout=600;ConnectionLifeTime=600;");
using (new ConnectionOpen(conn))
using (var ta = conn.BeginTransaction(IsolationLevel.Snapshot))
{
    IDbCommand command = conn.CreateCommand("SELECT * from stock;");
    command.SetTransaction(ta);
    IDataReader reader = command.ExecuteReader();

    int n = 0;
    while (!reader.IsClosed && reader.Read())
    {
        n++;

        if (n > 5000)
        {
            if (reader != null)
            {
                 ((NpgsqlDataReader)reader).Close();
            }
        }
     }
     ((NpgsqlDataReader)reader).Dispose();
     reader = null;
}

Я заметил, что считыватель данных не может действительно остановить.Кажется, что считыватель данных сначала читает все строки, а затем нормально возвращается.

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

Ответы [ 4 ]

9 голосов
/ 08 августа 2014

Я знаю, что эта ветка довольно старая, но я считаю, что правильный ответ на вопрос этого человека следующий:

command.Cancel(); //execute before closing the reader
reader.Close();

Вызывая DbCommand.Cancel (), вы указываете, что никакие дальнейшие записи не должны обрабатываться и что команда (включая базовый запрос) должна быть немедленно остановлена ​​и быстро выведена. Если вы не отмените команду, когда вы попытаетесь закрыть DbDataReader (или выйти из цикла / используя блок), и вы имеете дело с большим количеством возвращаемых записей, метод Close () заполняет значения для выходных параметров, возвращаемого значения и RecordsActed.

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

Части вышеуказанной информации были получены из: https://www.informit.com/guides/content.aspx?g=dotnet&seqNum=610

0 голосов
/ 25 января 2012

Это предположение.

Возможное решение 1

...
using (var ta = conn.BeginTransaction(IsolationLevel.Snapshot))
{
    IDbCommand command = conn.CreateCommand("SELECT * from stock;");
    command.SetTransaction(ta);
    IDataReader reader = command.ExecuteReader();

    int n = 5000;

    //put it in using
    using(IDataReader reader = command.ExecuteReader())
    {
        //read first N rows
        for(int i=0;i<n;i++)
        {           
            //get value from the columns of the current row
            for (i = 0; i < reader.FieldCount; i++)
            {
                Console.Write("{0} \t", reader[i]);
            }
        }
    }    
}

Возможное растворение 2

Используйте команду TOP sql, см. Примеры

0 голосов
/ 25 января 2012

Считыватель данных обычно возвращает порции данных с сервера базы данных (по крайней мере, так работает с SQL Server).Postgre SQL может вести себя по-разному под прикрытием.

Еще один способ атаковать это - загрузить данные как фоновую задачу ( BackgroundWorker , Задача и т. Д.).Таким образом, ваш поток пользовательского интерфейса остается отзывчивым, и не имеет значения, как читатель реализован под прикрытием.

0 голосов
/ 25 января 2012

Вы можете поместить разрыв в цикл while, но не уверены, если / как вы бы связали это с действием пользователя, чтобы они могли решить, когда выйти из цикла чтения.В качестве альтернативы вы могли бы реструктурировать код, чтобы он возвращал первое число строк x, а затем давал им кнопку продолжения, чтобы возвращать остальные или возвращать следующее число строк x.

...