2013-07-23 4 views
4

Провел много времени, но все же не может понять, как избежать кэширования в DbContext.EF DbContext. Как избежать кеширования?

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

Проблема в том, что результаты кэширования dbcontext. Например, у меня есть следующий код для запроса данных из моей базы данных:

using (TestContext ctx = new TestContext()) 
{ 
    var res = (from b in ctx.Buildings.Where(x => x.ID == 1) 
      select new 
      { 
       b, 
       flats = from f in b.Flats 
         select new 
         { 
          f, 
          people = from p in f.People 
          where p.Archived == false 
          select p 
         } 
      }).AsEnumerable().Select(x => x.b).Single(); 

} 

В этом случае, все в порядке: я получил то, что я хочу (только лицо с архивной == лжи).

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

  1. мой предыдущий результат, который Рез, будет добавлено по данным (там будут добавлены лица с архивными == тоже верно)
  2. новый результат будет содержать абсолютно все Индивидуальность человека, независимо от того, что архивации не сравняется

код этого запроса следующий:

using (TestContext ctx = new TestContext()) 
{ 
    var res = (from b in ctx.Buildings.Where(x => x.ID == 1) 
      select new 
      { 
       b, 
       flats = from f in b.Flats 
         select new 
         { 
          f, 
          people = from p in f.People 
          where p.Archived == false 
          select p 
         } 
      }).AsEnumerable().Select(x => x.b).Single(); 


    var newResult = (from b in ctx.Buildings.Where(x => x.ID == 1) 
       select new 
       { 
        b, 
        flats = from f in b.Flats 
          select new 
          { 
          f, 
          people = from p in f.People 
          where p.Archived == true 
          select p 
          } 
       }).AsEnumerable().Select(x => x.b).Single(); 
      } 

Кстати, я поставил LazyLoadingEnabled ложь в конструкторе TestContext.

Кто-нибудь знает, как решить эту проблему? Как я могу получить в своем запросе то, что я действительно пишу в своем linq для объекта?

P.S. @Ladislav, может быть, вы можете помочь?

Entity Model

+0

какой вы прочитали код. То есть, что заставляет вас говорить, что у вас есть все в newResult? Поскольку запрос запрашивает объект Building и не более. – tschmit007

+0

@ tschmit007 У здания есть свойство навигации, и каждая квартира имеет навигационное свойство People. Все это можно получить из newResult. – hvd

+0

действительно, но свойство навигации, которое вы получаете, не имеет ничего общего с вашим выбором ** S **, поскольку вы получаете только b ('select (x => x.b)'). Таким образом, вы получаете все здание в каждом случае. – tschmit007

ответ

8

Вы можете использовать метод AsNoTracking по Вашему запросу.

var res = (from b in ctx.Buildings.Where(x => x.ID == 1) 
     select new 
     { 
      b, 
      flats = from f in b.Flats 
        select new 
        { 
         f, 
         people = from p in f.People 
         where p.Archived == false 
         select p 
        } 
     }).AsNoTracking().AsEnumerabe().Select(x => x.b).Single(); 

Я также хочу отметить, что ваш AsEnumerable, вероятно, приносит больше вреда, чем пользы. Если вы удалите его, то Select(x => x.b) будет переведен на SQL. Как есть, вы выбираете все, а затем выбрасываете все, кроме x.b в память.

+0

AsNoTracking() неприменимо к запросу linq. Без AsEnumerable() детали не будут в результатах, которые мне не подходят. – DanTheMan

+0

Я не уверен, что вы подразумеваете под «запросом linq». Вы получаете сообщение об ошибке? – cadrell0

+0

«Если вы удалите его, Select (x => x.b) будет переведен на SQL» - Да, и этого не должно быть. Если он будет удален, квартиры здания не будут частью результатов запроса, потому что поставщик запросов видит, что 'flats' отбрасывается. – hvd

2

вы пытались что-то вроде:

ctx.Persons.Where(x => x.Flat.Building.Id == 1 && x.Archived == false); 

===== EDIT =====

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

Для вашей цели вам нужно будет загрузить данные, необходимые для создания вашего объекта filterd. Это выбрать здание, затем foreach Flat выберите неархивированных лиц.

Другим решением является использование слишком разных контекстов в дизайне «UnitOfWork».

+0

Нет, в реальных случаях мне нужен мой главный объект, а также детализированные детали и детали деталей, а может быть, их детали и тоже фильтры =) И, конечно, эта проблема кэширования стоит на моем пути, потому что у меня нет правильных данных – DanTheMan

+0

На самом деле, не понимаю, почему этот подход плох. – DanTheMan

+0

Если я напишу в качестве второго запроса запрос, который вы пишете (но только с этим условием Archived == true), у меня возникает следующая проблема: лица здания первого результата (** res **) будут добавлены человеком, у которого есть Arhived == true. Зачем??? Как защитить этот первый результат, добавив результаты следующих запросов? Кстати, для вашего ответа, я подумаю об этом – DanTheMan

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