В любом случае, требуется ли EF Core использовать два запроса для связанных данных вместо 1 или N + 1? - PullRequest
0 голосов
/ 12 апреля 2020

Простой сценарий Category и Product (один ко многим). Category имеет поле Description, которое может быть длинным текстом. Теперь мне нужно запросить список категорий со всеми их продуктами. Явная загрузка документации упоминает два очевидных подхода, которые не подходят в моем случае (см. Ниже).

Мой подход

var categories = await dc.Categories
    .AsNoTracking()
    .ToListAsync();

var catDict = categories.ToDictionary(q => q.Id);
var catIds = catDict.Keys;

var products = await dc.Products
    .Where(q => catIds.Contains(q.CategoryId))
    .ToListAsync();

foreach (var product in products)
{
    // Category.Products is initialized with empty List already
    catDict[product.CategoryId].Products.Add(product);
}

Этот подход требует только два запроса и делает не иметь избыточных данных. Я по-прежнему счастлив, даже если EF Core может вытащить JOIN, но вместо этого выбрать только Id из Category.

Есть ли в EF Core какой-либо метод / команда / запрос, который просит его запросить связанные данные таким образом ?


Другие упомянутые подходы:

1 подход к запросу

var categories = await dc.Categories
    .AsNoTracking()
    .Include(q => q.Products)
    .ToListAsync();

Этот генерирует только один вызов БД, но слишком много избыточных данных:

enter image description here

Подход N + 1 запросов

var categories = await dc.Categories
    .AsNoTracking()
    .ToListAsync();

foreach (var category in categories)
{
    category.Products = await dc.Products
        .Where(q => q.CategoryId == category.Id)
        .ToListAsync();
}

Этот подход удаляет избыточные данные, но теперь есть вызовы N + 1 DB.

1 Ответ

0 голосов
/ 12 апреля 2020

Если вы хотите запрашивать только определенные столбцы, вы можете использовать .Select, чтобы выбрать только те.

Рассмотрим пример, в котором используется .Include:

var categories = await dc.Categories
    .AsNoTracking()
    .Include(q => q.Products)
    .ToListAsync();

Так как вы не сделали Чтобы указать, какие столбцы выбрать, он извлекает *.

Если вы используете .Select, тогда ваш запрос будет извлекать только то, что вы хотите выбрать.

dc.Categories
    .Select(c => new Category
    {
        Id = c.Id,
        Products = c.Select(p => new Product
        {
            ... all product properties you want to retrieve
        })
    })
    .ToDictionary(c => c.Id)

(добавьте AsNoTracking и Async при необходимости)

См. также

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