Использование IDataReader для правильного чтения значений

Я использую datareader для извлечения некоторых значений из sqltable с помощью sqlcommand. Теперь, когда я впервые запускаю читатель, чтобы выбрать значения и присвоить их переменной RemovedRows, он работает отлично. Но когда он выполняется в следующий раз для заполнения переменной AddedRows, он ничего не возвращает. Теперь, если я поменяю местами переменные, у AddedRows будут значения, а у более поздних ничего не будет. Таким образом, в основном читатель выполняется один раз, а в следующий раз он не будет выполняться, а также не выдает никаких ошибок, например, читатель закрыт и т. Д.

using (IDataReader reader = _changeTable.ExecuteReader())
{
   RemovedRows = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] })
                       .Where(r => r.Operation.Equals("D")).Select(r => (long)r.LogID).ToList();

   AddedRows = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] })
                     .Where(r => r.Operation.Equals("I")).Select(r => (long)r.LogID).ToList();
}

public static IEnumerable<T> Select<T>(this IDataReader reader,
                                           Func<IDataReader, T> projection)
{
    while (reader.Read())
    {
        yield return projection(reader);
    }
}

Одним из решений является наличие значений читателя в new List<T> и доступ к новым значениям списка, не беспокоясь о состоянии читателя. Я могу создать список, но поскольку свойства имеют анонимный тип, я не могу получить к нему доступ.

Я создаю new List<T> и использую его так:

    public static List<T> CreateList<T>(params T[] elements)
    {
       return new List<T>(elements);
    }


 var values = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] }).ToList();
 var newList = Helper.CreateList(values);

 RemovedRows = newList.Where(r => r.Operation.Equals("D")).Select(r => (long)r.LogID).ToList();

Здесь он не позволяет мне получить доступ к свойствам Operation и LogID анонимного типа.

Итак, мой вопрос заключается в том, как я могу выполнить считыватель (код ниже) и использовать его значения позже после закрытия считывателя:

var values = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] }).ToList();

person Marshal    schedule 12.10.2015    source источник


Ответы (1)


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

string[] ops = {"D","I"};

IEnumerable<long> removedRows;
IEnumerable<long> addedRows;

using (IDataReader reader = _changeTable.ExecuteReader())
{
    var allRows = reader.Select(r => new { LogID = r["LogID"], Operation = r["SYS_CHANGE_OPERATION"] })
                        .Where(r => ops.Contains(r.Operation)
                        .ToList();

    removedRows = allRows.Where(r => r.Operation.Equals("D"))
                         .Select(r => (long)r.LogID);

    addedRows = allRows.Where(r => r.Operation.Equals("I"))
                       .Select(r => (long)r.LogID);
}

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

person D Stanley    schedule 12.10.2015
comment
Да, это работает. Я пробовал то же самое раньше, но я не уверен, почему это не сработало. Спасибо, я ценю ваш ответ. - person Marshal; 12.10.2015