LINQ-запрос с n + 1 вопросом - PullRequest
       35

LINQ-запрос с n + 1 вопросом

1 голос
/ 25 апреля 2019

У меня есть запрос с тремя подзапросами, и моя проблема заключается в том, что подзапросы выполняются для каждой страны (n + 1).

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

Я пытался включить Cities / Mountains / Rivers и запустить .ToList () для подзапросов, но безрезультатно.

// The CountryDto class I'm selecting to.
public class CountryDto
{
    public string CountryName { get; set; }
    public IEnumerable<CityDto> CityDtos { get; set; }
    public IEnumerable<MountainDto> MountainDtos { get; set; }
    public IEnumerable<RiverDto> RiverDtos { get; set; }
}
// The query
var query = _db.Countries
    .Select(country => new CountryDto
    {
        CountryName = country.Name,
        CityDtos = country.Citites
            .Where(city => city.Population > 10000)
            .Select(city => new CityDto
            {
                Name = city.Name,
            }),
        MountainDtos = country.Mountains
            .Where(mountain => mountain.Height > 100)
            .Select(mountain => new MountainDto
            {
                Name = mountain.Name,
            }),
        RiverDtos = country.Rivers
            .Where(river => river.Length > 1000)
            .Select(river => new RiverDto
            {
                Name = river.Name,
            }),
    })
    .Where(c => c.CityDtos.Any() || c.MountainDtos.Any() || c.RiverDtos.Any());

var totalCount = query.Count();
var countries = await query.ToListAsync();

Ответы [ 2 ]

0 голосов
/ 25 апреля 2019

Закончилось разделение запроса на .Where() часть для подсчета и .Select() часть для результата, что устранило мою проблему n + 1.

var query = await _db.Countries
    .Include(c => c.Cities)
    .Include(c => c.Mountains)
    .Include(c => c.Rivers)
    .Where(c => c.Cities.Any(city => city.Population > 10000)
        || c.Mountains.Any(mountain => mountain.Heigh > 1000)
        || c.River.Any(river => river.Length > 100000))
    .Where(c => c.Cities.Any() || c.Mountains.Any() || c.Rivers.Any())
    .ToListAsync();

var totalCount = query.Count();

var countries = query
    .Select(country => new CountryDto
    {
        CountryName = country.Name,
        CityDtos = country.Citites
            .Select(city => new CityDto
            {
                Name = city.Name,
            }),
        MountainDtos = country.Mountains
            .Select(mountain => new MountainDto
            {
                Name = mountain.Name,
            }),
        RiverDtos = country.Rivers
            .Select(river => new RiverDto
            {
                Name = river.Name,
            }),
    })
    .ToList();
0 голосов
/ 25 апреля 2019

Entity Framework Core поддерживает части запроса, оцениваемые на клиенте, и части его, передаваемые в базу данных.Поставщик базы данных должен определить, какие части запроса будут оцениваться в базе данных.

В вашем случае, я думаю, все .Any части оцениваются на стороне клиента.Вы можете настроить свой код на выдачу исключения для оценки клиента.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;")
        .ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}

Для получения дополнительной информации https://docs.microsoft.com/en-us/ef/core/querying/client-eval

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