2016-01-15 4 views
1

Я хочу использовать шаблон async/await в моем ASP.NET MVC-контроллере. Я получаю ошибкуВ MVC-контроллере, требующем async для возврата EntityFramework CodeFirst data

ObjectContext экземпляр был размещенной и больше не может быть использован

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

public class SpeakerController : Controller 
    { 
     public async Task<ActionResult> Index() 
     { 
      using (var context = new MultiTenantContext()) 
      { 
       var speakersAll = await context.Speakers.ToListAsync(); 
       return View("Index", speakersAll); 
      } 
     } 

Решение Найдено:

private MultiTenantContext context = new MultiTenantContext(); 

    public async Task<ActionResult> Index() 
    { 
      var speakersAll = await context.Speakers.ToListAsync(); 
      return View("Index", speakersAll); 
    } 

Как я уже сказал в приведенном ниже комментарии, вытягивание контекста из использования приводит к тому, что он не может быть удален, когда выполняется ToListAsync().

+0

Какая строка выдает ошибку? – Carl

+0

Я только что нашел пример, который показывает, что я могу переместить контекст в контроллер, например: private MultiTenantContext context = new MultiTenantContext(); и это решило проблему здесь. Теперь я перехожу к проблеме с кешем. –

+2

Вам следует опубликовать, как вы решили проблему как ответ для всех, кто может столкнуться с вашей должностью в будущем. – drneel

ответ

3

Вы должны избегать использования отложенной загрузки в веб-приложений, потому что цель состоит в том, чтобы свести к минимуму время ответа HTTP-запроса, и это лучше всего достигается с меньшим количеством запросов к базе данных. Особенно с MVC и/или веб-API, где у вас очень гранулированные методы действий, в большинстве случаев должно быть возможно точно определить, что ваши требования к данным, и включить их в одно или несколько запросов или запросов. Это снижает нагрузку на сервер базы данных и обеспечивает лучшую производительность для ваших веб-запросов.

Что касается использования утверждений и dbcontexts, вы не должны создавать экземпляры dbcontexts в своем контроллере, если сможете это сделать. Гораздо лучше их вводить, и пусть ваш контейнер определит, как управлять своей жизнью. Как правило, вы хотите иметь ровно один экземпляр dbcontext для каждого запроса, который будет доступен для всех (как бы мало это ни было) запросов, которые вам нужно EF для выполнения в течение срока действия запроса. Если вы используете StructureMap (мое предпочтение), вы бы добиться этого с:

For<DbContext>.HybridHttpOrThreadLocalScoped().Use<MyContext>(); 

(Обратите внимание, что этот синтаксис обновляется с StructureMap 4)

Если вы не уверены, доверяете ли вы мою рекомендацию , считают, что EF7 продолжает эту рекомендацию и затрудняет работу с EF7 и MVC 6 без, используя инъекцию зависимостей, чтобы заставить разработчиков делать правильные вещи (попадая в «яму успеха», как бы). См. Этот учебник EF7/MVC6 в официальных документах asp.net для примера (http://docs.asp.net/projects/mvc/en/latest/tutorials/mvc-with-entity-framework.html).

Отрывок:

Обратите внимание, что мы не какое-либо значение для Logger и BookContext. Подсистема впрыска (DI) автоматически устанавливает эти свойства во время выполнения. DI также обрабатывает время жизни объекта, поэтому вам не нужно вызывать Dispose. Для получения дополнительной информации см. Зависимость Инъекция.

+0

уже добавил +1, но хотел перезвонить с этим +1. –

+0

Спасибо @ssmith Любое мнение о async или кеше? –

+0

Я поклонник обоих. async Я думаю, что у вас есть. вы можете использовать атрибут [OutputCache] (для полного вывода) или через CachedRepository (http://ardalis.com/building-a-cachedrepository-via-strategy-pattern) для данных. – ssmith

1

Если вы лениво загружаете Speaker.Sessions, ваш контекст давно ушел на время его использования, поэтому проблема.

Попробуйте вместо этого:

await context.Speakers.Include(x => x.Sessions).ToListAsync(); 

для обеспечения Сессия загружается до вашего контекст выходит из области видимости.

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

Хотя это не проблема - вы не должны смешивать ленивым-загрузку с асинхронным-ждут в EF: Why Does Await Not Appear to Prevent Second Operation on EF Context

+0

Добавляет ли «виртуальное» ключевое слово в списки, делает то же самое, что и .Include? То есть, Speakers определяется как виртуальный список (а не только список) –

+0

Не совсем; они более приветливы. Как правило, виртуальный позволяет EF lazy-load свойство, а Include просит его скорее загружать свойства, не имеющие лени, загруженные в ваше определение Include. http://stackoverflow.com/questions/15247614/understanding-code-first-virtual-properties достаточно хорошо объясняет виртуальную часть. – sellotape

Смежные вопросы