Как лучше всего очистить SQLDataReader при использовании linq

У меня есть метод, который возвращает средство чтения данных. Обычно я бы обернул использование вокруг средства чтения данных, чтобы оно было хорошо утилизировано после того, как я его повторю. Проблема в том, что я решил использовать средство чтения данных с помощью Linq, а это означает, что отложенное выполнение приводит к тому, что средство чтения удаляется раньше. Существует ли правильный шаблон для использования и удаления средства чтения данных с помощью Linq без необходимости создания полной коллекции его содержимого?

using (System.Data.SqlClient.SqlDataReader reader = CallStoredProcedure())
{
    return reader.Cast<System.Data.Common.DbDataRecord>().Select(rec => new ObjectModel.CollectorSummaryItem()
    {
        CollectorID = (int)rec[0],
        Name = rec.IsDBNull(1) ? null : rec.GetString(1),
        Information = rec.IsDBNull(2) ? null : rec.GetString(2)
    });
}

person Jeremy    schedule 23.04.2013    source источник
comment
Вы пробовали просто делегировать чтение? Создайте метод, который принимает IDataRecord и создает ваш объект. Построить список из него и вернуть этот список?   -  person Sinaesthetic    schedule 24.04.2013


Ответы (2)


Вам нужно на самом деле читать из считывателя внутри блока использования:

using (System.Data.SqlClient.SqlDataReader reader = CallStoredProcedure())
{
    while (reader.Read())
    {
        yield return new ObjectModel.CollectorSummaryItem()
        {
            CollectorID = (int)reader[0],
            Name = reader.IsDBNull(1) ? null : reader.GetString(1),
            Information = reader.IsDBNull(2) ? null : reader.GetString(2)
        };
    }
}

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

person Joel Coehoorn    schedule 23.04.2013

Здесь стреляют от бедра. Это также должно помочь вам отделить логику чтения.

public IEnumerable<MyObject> ExecuteNonQuery(...)
{
  ...
  using(var reader = comm.ExecuteReader())
  {
    var results = new List<MyObject>();
    return reader
            .Cast<System.Data.Common.DbDataRecord>()
            .Select(rec => GetFromReader(rec))
            .ToList();
  }
}

public MyObject GetFromReader(IDataRecord rdr)
{
   return new MyObject { Prop1 = rdr["prop1"], Prop2 = rdr["prop2"] };
}
person Sinaesthetic    schedule 24.04.2013
comment
Есть небольшая проблема с этим кодом. LINQ ленив и не будет оценивать лямбда-выражение до тех пор, пока вы не перечислите IEnumerable, что, вероятно, будет за пределами данного метода. К тому времени оператор using избавился бы от reader. Если вы использовали такой метод, как ToList() после оператора Select, чтобы принудительно перечислить IEnumerable внутри блока using, это может сработать. - person BrainStorm.exe; 05.12.2013