2013-03-13 5 views
15

Вот мой пример кода, который я использую для извлечения данных из базы данных: на DAO слой:Я задаюсь вопросом о состоянии связи и влияния на производительность кода путем «выход» в то время как итерация объекта чтения данных

public IEnumerable<IDataRecord> GetDATA(ICommonSearchCriteriaDto commonSearchCriteriaDto) 
{ 
    using(DbContext) 
    { 
     DbDataReader reader = DbContext.GetReader("ABC_PACKAGE.GET_DATA", oracleParams.ToArray(), CommandType.StoredProcedure); 
     while (reader.Read()) 
     { 
      yield return reader; 
     } 
    } 
} 

на слое BO я звоню выше метод, как:

List<IGridDataDto> GridDataDtos = MapMultiple(_costDriversGraphDao.GetGraphData(commonSearchCriteriaDto)).ToList(); 

на картографа методе слой MapMultiple определяется как:

public IGridDataDto MapSingle(IDataRecord dataRecord) 
{ 
    return new GridDataDto 
    { 
     Code = Convert.ToString(dataRecord["Code"]), 
     Name = Convert.ToString(dataRecord["Name"]), 
     Type = Convert.ToString(dataRecord["Type"])  
    }; 
} 
public IEnumerable<IGridDataDto> MapMultiple(IEnumerable<IDataRecord> dataRecords) 
{ 
    return dataRecords.Select(MapSingle); 
} 

Приведенный выше код работает хорошо и хорошо, но мне интересно узнать о двух проблемах с вышеуказанным кодом.

  1. Как долго будет подключаться устройство чтения данных?
  2. Когда я рассматриваю только коэффициент эффективности кода, полезно ли использовать «yield return» вместо добавления записи в список и возврата всего списка?

ответ

12
  1. Ваш код не показывает, где вы открываете/закрываете соединение; но читатель здесь фактически будет открыт только , пока вы повторяете данные. Отсроченное исполнение и т. Д. Единственный бит вашего кода, который делает это, - .ToList(), так что все будет хорошо. В более общем случае да: читатель будет открыт на время, которое вы предпримете для его итерации; если вы делаете .ToList(), что будет минимальным; если вы делаете foreach и (для каждого элемента), делаете внешний HTTP-запрос и ждете 20 секунд, тогда да - он будет открыт дольше.
  2. Оба имеют свои преимущества; небуферизованный подход отлично подходит для огромных результатов, которые вы хотите обрабатывать как поток, без необходимости загружать их в один список в памяти (или даже иметь все из них в памяти за раз); возврат списка быстро закрывает соединение и позволяет избежать случайного использования соединения, в то время как у него уже есть открытый считыватель, но он не идеален для больших результатов.

Если вы вернете блок итератора, решать, что разумно; если вы всегда возвращаете список, у них не так много вариантов. Третий способ (что мы делаем в dapper) - сделать свой выбор; у нас есть необязательный параметр bool, который по умолчанию «возвращает список», но который вызывающий может изменить, чтобы указать «вернуть блок итератора»; в основном:

bool buffered = true 

в параметрах, а также:

var data = QueryInternal<T>(...blah...); 
return buffered ? data.ToList() : data; 

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

+0

спасибо за ваш быстрый ответ и помощь! –

3

Как долго будет подключаться устройство чтения данных?

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

Когда я рассматриваю только коэффициент эффективности кода, полезно ли использовать yield return вместо добавления записи в список и возврата всего списка?

Это зависит от нескольких факторов:

  • Если вы не планируете получать весь результат, yield return поможет вам сэкономить на количестве данных, передаваемых по сети
  • Если вы не планирование преобразования возвращенных данных в объекты или использование нескольких строк для создания одного объекта, yield return поможет вам сэкономить на памяти, используемой в пиковой точке использования вашей программы.
  • Если вы планируете повторять набор результатов enture в виде период времени, не будет никаких штрафных санкций за использование yield return. Если итерация длится значительное количество времени на нескольких параллельных потоках, количество открытых курсоров на стороне РСУБД может быть превышено.
0

Этот ответ игнорирует недостатки в показанной реализации и охватывает общую идею.

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