Как использовать Skip () и Take () для некоторого свойства DbSet <Class>, которое является ICollection <> - PullRequest
2 голосов
/ 21 июня 2020

У меня есть класс DbSet:

public class Manufacturer
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
    public virtual Category Category { get; set; }
    public virtual ICollection<Product> Products { get; set; }
}

Я знаю, что могу использовать Skip() и Take() для ограничения manufacturers. Но мое требование - ограничить Products всех manufacturers. Я использую что-то вроде этого, но это не работает

var manufacturers = await _context.Manufacturers.Where(x => x.Products.Take(10))
                    .ToListAsync(); 

PS: Я использую ленивую загрузку (не нетерпеливую загрузку)

Ошибка компиляции:

Невозможно неявно преобразовать тип System.Collections.Generi c .IEnumerable 'to' bool 'Невозможно преобразовать лямбда-выражение в предполагаемый тип делегата, поскольку некоторые из возвращаемых типов в блоке не могут быть неявно преобразованы в тип возвращаемого делегата

Как я могу получить все производители, но ограниченное количество товаров в них?

Ответы [ 3 ]

2 голосов
/ 21 июня 2020

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

var manufacturers = await _context.Manufacturers.Include(m => m.Products).ToListAsync();

foreach(var m in manufacturers)
{
    m.Products = m.Products.Take(10).ToList();
}

Это получит все продукты для каждого производителя из БД, а затем сохранит только первые 10.

2 голосов
/ 21 июня 2020

Вы можете сначала загрузить объект Manufacturer без списка Product (то есть без вызова Include()), а затем запустить отдельный запрос, чтобы загрузить только те продукты, которые вам нужны для указанного объекта c Manufacturer . EF автоматически обновит свойства навигации. См. Следующий пример (авторы могут иметь несколько сообщений в этом примере):

using (var context = new MyContext())
{
    Author author = context.Author.First();
            
    Console.WriteLine(context.Post.Where(it => it.Author == author).Count());
            
    context.Post.Where(it => it.Author == author).Take(2).ToList();
            
    Console.WriteLine(author.Posts.Count());
}

Будет получен следующий результат:

3
2

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

Для строки Author author = context.Author.First();:

SELECT `a`.`Id`, `a`.`Name`
FROM `Author` AS `a`
LIMIT 1

Для строки context.Post.Where(it => it.Author == author).Count():

SELECT COUNT(*)
FROM `Post` AS `p`
INNER JOIN `Author` AS `a` ON `p`.`AuthorId` = `a`.`Id`
WHERE `a`.`Id` = 1

Для context.Post.Where(it => it.Author == author).Take(2).ToList(); line:

SELECT `p`.`Id`, `p`.`AuthorId`, `p`.`Content`
FROM `Post` AS `p`
INNER JOIN `Author` AS `a` ON `p`.`AuthorId` = `a`.`Id`
WHERE `a`.`Id` = 1
LIMIT 2

Однако вы должны проделать этот трюк для каждой отдельной Manufacturer сущности, чтобы она загружала только десять связанных Product сущностей. Это может привести к появлению 1 + N запросов SELECT .

0 голосов
/ 21 июня 2020

Попробуйте более длинный способ:

_await _context.Manufacturers.Select(x => 
{
  x.Products = x.Products.Take(10).ToList();
  return x;
}).ToListAsync();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...