DataReader или DataSet при перемещении нескольких наборов записей в ASP.NET

У меня есть страница ASP.NET, в которой есть куча элементов управления, которые необходимо заполнить (например, выпадающие списки).

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

Я мог бы вернуть несколько таблиц в DataSet, или я мог бы вернуть DataReader и использовать ".NextResult", чтобы поместить каждый результирующий набор в пользовательский бизнес-класс.

Возможно, я увижу достаточно большое преимущество в производительности, используя подход DataReader, или я просто должен использовать подход DataSet?

Любые примеры того, как вы обычно справляетесь с этим, будут оценены.

Ответ 1

  • Если для вашей базы данных имеется более 1000 записей.
  • Если вас не очень интересует пользовательское хранение и пользовательский пейджинг "Для GridView"
  • Если ваш сервер имеет напряжение памяти.
  • Если нет проблем с подключением к вашей базы данных каждый раз, когда эта страница называется.

Тогда я думаю, что лучше использовать DataReader.

еще

  • Если у вас есть менее 1000 записей, которые можно извлечь из вашей базы данных.
  • Если вас интересует хранения и подкачки "Для GridView "
  • Если ваш сервер не имеет памяти стресс.
  • Если вы хотите подключиться к своему База данных только один раз и получить преимущества кэширования.

Тогда я думаю, что лучше использовать DataSet.

Я хожу, что я прав.

Ответ 2

Всегда помещайте свои данные в классы, определенные для конкретного использования. Не пропускайте DataSets или DataReaders.

Ответ 3

Если ваш сохраненный proc возвращает несколько наборов, используйте DataReader.NextResult для перехода к следующему фрагменту данных. Таким образом, вы можете получить все свои данные, загрузить их на свои объекты и как можно скорее закрыть читателя. Это будет самый быстрый способ получить ваши данные.

Ответ 4

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

Я бы использовал 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 Wrapper

У меня есть сообщение в блоге (ссылка выше), которая идет намного подробнее, и я буду генерировать генератор исходного кода для этого и другого кода уровня DataAccess.

Вы можете использовать ту же технику для DataTables (генератор кода создает код), поэтому вы можете рассматривать их как строго типизированный DataTable без накладных расходов на то, что VS.NET предоставляет из коробки.

Имейте в виду, что существует только один экземпляр класса-оболочки. Таким образом, вы не создаете сотни экземпляров класса, чтобы выбросить его.

Ответ 5

Сопоставьте DataReader с промежуточными объектами, а затем привяжите свои элементы управления с помощью этих объектов. В некоторых случаях можно использовать DataSets, но это мало и далеко, когда у вас есть веские причины "просто получать данные". Независимо от того, что вы делаете, не передавайте DataReader в свои элементы управления, чтобы связывать (не то, что вы сказали, что считаете это).

Мое личное предпочтение было бы использовать ORM, но если вы собираетесь перевести свой доступ к данным, я думаю, вам следует предпочесть сопоставление DataReaders с объектами с использованием DataSets. Использование .NextResult как способ ограничить себя от попадания в базу данных несколько раз - это обоюдоострый меч, но так разумно выбирать. Вы обнаружите, что повторяете себя, если пытаетесь создать procs, которые всегда захватывают именно то, что вам нужно, используя только один вызов в базе данных. Если ваше приложение - всего несколько страниц, это, вероятно, хорошо, но все может быстро выйти из-под контроля. Лично я предпочел бы иметь один proc для типа объекта, а затем несколько раз ударять по базе данных (один раз для каждого типа объекта), чтобы максимизировать ремонтопригодность. Здесь ORM светит, потому что хороший будет генерировать Sql, который в большинстве случаев даст вам именно то, что вы хотите, с одним вызовом.

Ответ 6

Если вы не заинтересованы в обновлении или удалении записей, которые вы извлекли из базы данных, я бы предложил использовать DataReader. В основном DataSet внутренне использует несколько Datareaders, поэтому DataReader должен давать вам хорошее преимущество в производительности.

Ответ 7

В почти каждой ситуации DataReader - лучшее решение для чтения из базы данных. DataReader быстрее и требуют меньше памяти, чем DataTable или DataSet s.

Кроме того, DataSet может часто приводить к ситуациям, в которых модель OO сломана. Он не очень объектно ориентирован на то, чтобы передавать реляционные данные/схемы вместо объектов, которые умеют манипулировать этими данными.

Итак, для расширяемости, масштабируемости, модульности и производительности, всегда используйте DataReader, если вы считаете себя настоящим программистом ™;)

Проверьте ссылки для фактов и обсуждения этих двух на практике и теории.

Ответ 8

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

В отношении того, нужно ли вам когда-либо беспокоиться о множестве наборов результатов, мудрость заключается в том, что вы не должны, но я могу представить разумный класс исключений из этого правила: (плотно) связанные результирующие наборы. Вы, конечно же, не хотите добавлять запрос для возврата того же набора вариантов для раскрывающегося списка, который повторяется на сотнях или даже десятках страниц в вашем приложении, но несколько наборов, которые используются узко, могут быть разумно объединены. Например, в настоящее время я создаю страницу для отображения нескольких наборов "несоответствий" для партии данных ETL. Ни один из этих запросов, скорее всего, не будет использоваться в других местах, поэтому было бы удобно инкапсулировать их в виде простого "получить расхождения" sproc. С другой стороны, лучшая производительность при этом может быть незначительной по сравнению с обходной архитектурой с естественным однострочным однокомпонентным набором ORM или ручным списком доступа к данным.

Ответ 9

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

Лично с несколькими раскрывающимися папками я обычно перебираю отдельные куски данных для его получения, вместо того, чтобы хранить хранимую процедуру, которая возвращает 5 наборов результатов.

Ответ 10

Взгляните на TableAdapters, которые доступны с .NET 2.0 и выше. То, что они делают, дает вам силу строго типизированного DataTable и позволяет сопоставить метод Fill с ним, который будет использовать DataReader для его загрузки. Ваш метод заполнения может быть существующими хранимыми процедурами, вашим собственным AdHoc SQL или даже позволить мастеру генерировать AdHod или хранимую процедуру для вас.

Вы можете найти это, запустив новый объект XSD DataSet в своем проекте. Для таблиц, которые используются не только для поиска, вы также можете сопоставлять методы insert/update/delete с TableAdapter.