Видя, что ни один ответ еще не отмечен, хотя уже есть много хороших ответов, я подумал, что добавлю еще два бита.
Я бы использовал DataReaders, так как они немного быстрее (если вам нужна производительность или вам нужно столько, сколько вы можете получить). Большинство проектов, над которыми я работал, содержат миллионы записей в каждой из таблиц, и производительность вызывает беспокойство.
Некоторые люди говорят, что отправлять DataReader между слоями не очень хорошая идея. Лично я не вижу в этом проблемы, поскольку «DbDataReader» технически не привязан (или не должен быть) к базе данных. То есть вы можете создать экземпляр DbDataReader без необходимости в базе данных.
Почему я это делаю по следующим причинам:
Часто (в веб-приложении) вы генерируете либо Html, либо Xml или JSON, либо какое-то другое преобразование ваших данных. Так зачем переходить от DaraReader к какому-либо объекту POCO только для преобразования его обратно в XML или JSON и отправки по сети. Этот тип процесса обычно требует 3 преобразования и загрузку экземпляров объекта только для того, чтобы выбросить их почти мгновенно.
В некоторых ситуациях это нормально или ничего не поделаешь. Мой уровень данных обычно отображает два метода для каждой хранимой процедуры, которую я имею в системе. Один возвращает DbDataReader, а другой возвращает DataSet / DataTable. Методы, которые возвращают DataSet / DataTable, вызывают метод, возвращающий DbDataReader, а затем используют метод «Load» для DataTable или адаптер для заполнения набора данных. Иногда вам нужны DataSets, потому что вам, вероятно, придется каким-то образом переназначить данные или вам нужно запустить другой запрос, и если у вас не включен MARS, вы не можете открыть DbDataReader и запустить другой запрос.
Теперь есть некоторые проблемы с использованием DbDataReader или DataSet / DataTable, обычно это ясность кода, проверка времени компиляции и т. Д. Вы можете использовать классы-обертки для вашего datareader и фактически вы можете использовать свои DataReaders с IEnumerable с ними. Действительно крутая способность. Так что вы не только получаете строгую типизацию и читабельность кода, но и IEnumerable!
Так что класс может выглядеть следующим образом.
public sealed class BlogItemDrw : BaseDbDataReaderWrapper
{
public Int64 ItemId { get { return (Int64)DbDataReader[0]; } }
public Int64 MemberId { get { return (Int64)DbDataReader[1]; } }
public String ItemTitle { get { return (String)DbDataReader[2]; } }
public String ItemDesc { get { if (DbDataReader[3] != DBNull.Value) return (String)DbDataReader[3]; else return default(String); } }
public DateTime ItemPubdate { get { return (DateTime)DbDataReader[4]; } }
public Int32 ItemCommentCnt { get { return (Int32)DbDataReader[5]; } }
public Boolean ItemAllowComment { get { return (Boolean)DbDataReader[6]; } }
public BlogItemDrw()
:base()
{
}
public BlogItemDrw(DbDataReader dbDataReader)
:base(dbDataReader)
{
}
}
Упаковщик DataReader
У меня есть запись в блоге (ссылка выше), которая более детально описана, и я буду делать генератор исходного кода для этого и другого кода уровня DataAccess.
Вы можете использовать ту же технику для DataTables (генератор кода создает код), чтобы вы могли обращаться с ними как со строго типизированной DataTable без дополнительных затрат, предоставляемых VS.NET из коробки.
Имейте в виду, что существует только один экземпляр класса-оболочки. Таким образом, вы не создаете сотни экземпляров класса только для того, чтобы выбросить его.