Как запретить Entity Framework запрашивать дважды при доступе к IQueryable - PullRequest
0 голосов
/ 05 июля 2019

Я написал API с использованием Entity Framework и пытаюсь оптимизировать его обращения к базе данных.

Когда я получаю объект (мы назовем его Page), у которого есть много связанных объектов, я использую .Include() метод linq, который предотвращает вызовы N + 1.

Мой основной объект (назовем его Book) имеет много Page. Когда я получаю Book из db, я делаю это 2 раза на моей фабрике DAL, чтобы предотвратить массивный одиночный запрос (у моего Page есть 10 связанных объектов, а у моего Book есть 4):

public async Task<IBook>GetById(int myBookId) {
    var Pages = myDbContext.Page
                           .Where(x => x.BookId == myBookId && x.IsChapter)
                           .Include(x => x.prop1)
                           .Include(x => x.prop2) etc

    var myBook = await myDbContext.Book 
                                  .Where(x => x.Id == myBookId)
                                  .Include(x => x.bprop1)
                                  .FirstOrDefaultAsync()

    myBook.Pages = Pages.ToList();
}

Это работает, и мой сгенерированный SQL - именно то, что я хочу:

select * 
from Page 
where page_Chapter = 1 and page_bookId = @EntityKeyValue1

и

select * 
from Book 
where book_Id = @EntityKeyValue1

с *, фактически являющимся столбцами связанных таблиц.

Теперь моя проблема в том, что, когда я пытаюсь преобразовать мой объект из объекта базы данных в передний объект, делается новый запрос для Page, который равен

select * 
from page 
where page_bookId = @EntityKeyValue1.

Вот как я делаю преобразование:

public async Task<BookModel> GetBookById(int id)
{
       using (var context = _dalFactory.GetNewContext(EPurpose.SELECT))
       {
                var t = (await _dalFactory.GetBookRepository(context).GetById(id)).ConvertToModel();

                return t;
       }
}

и мой Convert() метод:

public static BookModel Convert(this Book book)
{
        if (book == null)
            return null;

        BookModel toReturn = new BookModel
        {
           toReturn.Id = book.Id,
           toReturn.intP = book.intP,
           ...  
        };

        if (book.Page != null)
        { 
           var PageModelList = new List<PageModel>();
           //then I convert my book.Page to PageModel list and assign toReturn.Page to that.
        }
}

Запрос сделан, как только я проверю book.Page != null.

Есть мысли о том, как предотвратить двойной запрос? На самом деле мне просто нужно около 10% Page, полученных в последнем запросе

1 Ответ

0 голосов
/ 06 июля 2019

Использование .AsNoTracking() может решить вашу проблему, при условии, что вы не планируете обновлять эти объекты позже.

 var myBook = await myDbContext.Book
                                  .AsNoTracking()
                                  .Where(x => x.Id == myBookId)
                                  .Include(x => x.bprop1)
                                  .FirstOrDefaultAsync();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...