2016-04-26 2 views
1
public IQueryable<Application> GetAppById(Guid Id)      
{ 
     return Repository.Query().Where(c => c.Id == Id).Select(c => c.App) 
} 

Я получил этот код выше, и кажется, что он не возвращается правильно. Если я вызываю другой репозиторий в БД, такой как Repository2.Query(). Где (?? код ??). Я получил ошибку ниже.Ошибка при вызове другого репо - «Существует уже открытый DataReader, связанный с этой командой, который должен быть закрыт первым»

ОШИБКА: { «Существует уже открытая DataReader, связанные с этой командой, которая должна быть закрыта первая»}


Однако, когда я изменить возвращение к ICollection <> это ответы прямо ,

public ICollection<Application> GetAppById(Guid Id)      
{ 
     return Repository.Query().Where(c => c.Id == Id).Select(c => c.App).ToList(); 
} 

отладить IQueryable возвращение, нет никакой ошибки, но я не смог найти найти данные, которые он извлекает. Ошибка возникает при вызове другого в репо.

+0

Вы открываете DataReader в том же соединении (или вызываете какой-либо код, который делает) где-либо еще в вашей программе до этой точки? Возможно, вы пытаетесь использовать DbContext из нескольких потоков? – yaakov

+0

I debug IQueryable return, нет ошибки, но я не смог найти найденные данные. Ошибка возникает при вызове другого в репо. – user1960948

+0

У меня такое ощущение, что различие не в «IQueryable», а в отношении «ICollection», но в том, что вы вызываете '.ToList()', который будет полностью оценивать ваш ленивый запрос на месте. Является ли 'Repository.Query()' ваш собственный код или это стандартная структура (например, EntityFramework))? – yaakov

ответ

2

Сообщение верно; вы разрешили выполнение двух команд одновременно. Первый показанный метод возвращает «запрос» - он фактически не выполняет ничего, пока вы его не перейдете - и откроется до вас stop iterating it. Действительно, вся цель IQueryable<T> заключается в том, чтобы доставить дополни- тельную композицию до ее выполнения. Поэтому, предполагая, что вы используете foreach, запрос активен в течение всего времени foreach, , а не звонок по телефону GetAppById. Так что, если вы делаете классический «N + 1»:

foreach(var row in SomeOuterQuery(...)) { // N+1, not a great idea 
    SomeInnerQuery(row, ...); 
} 

то вы абсолютно бежите несколько одновременных команд.

Есть три основные исправления:

  • запустить первый запрос в полном, а затем перебирать в результаты - это то, что добавление ToList делает: он перемещает foreach к внутриGetAppById
  • включить «MARS» (несколько активных наборов результатов) - обратите внимание: это не совет, просто «это будет работать» (но: не все, что работает, это хорошая идея)
  • реструктурировать работу, чтобы никогда не требовалось «N» в «N + 1», например, путем получения дополнительных данных в то же время, что и внешний список (например, несколько результирующих сеток из одного запроса)
+0

отлично .. это действительно помогает .. ty – user1960948