Как работать с большими наборами результатов с Linq to Entities? - PullRequest
6 голосов
/ 16 июня 2010

У меня довольно сложный запрос linq to entity, который я отображаю на веб-сайте. Он использует пейджинг, поэтому я никогда не вынимаю более 50 записей за раз.

Но я также хочу дать пользователю возможность экспортировать полные результаты в Excel или другой формат файла.

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

Есть ли способ обработки 1 записи в наборе результатов linq за раз, как если бы вы могли работать с устройством чтения данных, чтобы в памяти одновременно сохранялась только 1 запись?

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

У кого-нибудь есть ссылка на то, что я мог прочитать, чтобы проверить это?

Буду признателен за любую помощь.

Спасибо

Ответы [ 2 ]

5 голосов
/ 16 июня 2010

установите ObjectContext на MergeOption.NoTracking (так как это операция только для чтения).Если вы используете тот же ObjectContext для сохранения других данных, Отсоедините объект от контекста.

как отсоединить

foreach( IQueryable)
{
  //do something 
  objectContext.Detach(object);
}

Редактировать : если вы используете опцию NoTracking, нет необходимости отсоединять

Edit2 : я писал Мэтту Уоррену об этом сценарии.И я публикую здесь соответствующие частные переписки с его одобрением

Результаты, полученные с сервера SQL, могут даже не быть получены сервером.Запрос запущен на сервере, и первая партия результатов передается клиенту, но больше не генерируется (или они не кэшируются на сервере), пока клиент не запросит продолжить их чтение.Это то, что называется режимом «пожарный курсор» или иногда называется потоковой передачей.Сервер отправляет их так быстро, как может, и клиент читает их так быстро, как может (ваш код), но под ним есть протокол передачи данных, который требует подтверждения от клиента для продолжения отправки большего количества данных.

Поскольку IQueryable наследуется от IEnumerable, я считаю, что основной запрос, отправляемый на сервер, будет таким же.Однако, когда мы делаем IEnumerable.ToList(), считыватель данных, который используется базовым соединением, начнет заполнять объект, объекты загружаются в домен приложения и могут исчерпать память, эти объекты еще не могут быть удалены.

Когда вы используете foreach и IEunmerable, считыватель данных читает набор результатов SQL по одному, объекты создаются и затем удаляются.Базовое соединение может получать данные в чанках и может не отправлять ответ обратно SQL Server, пока не будут прочитаны все чанки.Следовательно, вы не встретите исключение «нехватка памяти»

Edit3 :

Когда ваш запрос выполняется, вы фактически можете открыть SQL Server «Activity Monitor» исм. запрос, состояние задачи как SUSPENDED и тип ожидания как Async_network_IO, который фактически указывает, что результат находится в сетевом буфере SQL Server.Вы можете прочитать больше об этом здесь и здесь

2 голосов
/ 01 июля 2010

Посмотрите на возвращаемое значение запроса LINQ. Это должно быть IEnumerable <> , которое одновременно загружает только один объект. Если вы затем используете что-то вроде .ToList(), все они будут загружены в память. Просто убедитесь, что ваш код не поддерживает список или не использует более одного экземпляра за раз, и все будет в порядке.

Редактировать: Чтобы добавить к тому, что люди говорили о foreach ... Если вы делаете что-то вроде:

var query = from o in Objects
            where o.Name = "abc"
            select o;

foreach (Object o in query)
{
   // Do something with o
}

Часть запроса использует отложенное выполнение ( см. Примеры ), поэтому объекты еще не находятся в памяти. Foreach перебирает результаты, но получает только один объект за раз. query использует IEnumerator , который имеет Reset() и MoveNext(). Foreach вызывает MoveNext () каждый раунд до тех пор, пока больше не будет результатов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...