Ho classi ef come questa:
class Product
{
public int ProductId {set; get;}
...
public List<ProductBannedIn> BannedIn;
}
public class ProductBannedIn
{
public int ProductId {set; get;}
public Product Product {set; get;}
public int CountryId {set; get;}
public Country Country {set; get;}
}
E vuoi fare una richiesta come:
... //query - added some filters before
var products = query.Include(x => x.BannedIn)
.Join(context.ProductTranslation
.Where(x => x.LanguageId == language.LanguageId),
product => product.ProductId,
translation => translation.Product.ProductId,
(x,y) => new {
Id = x. ProductId,
Name = y.Name,
Description = y.Description,
Type = x.TypeId,
BannedIn = x.BannedIn.Select(b => b.CountryId),
}).ToList();
Problema: il problema è che quando raccolgo ad esempio 1000 prodotti questa parte
BannedIn = x.BannedIn.Select(b => b.CountryId)
fare query per ogni riga ed è molto lento. Quello che ho visto nel debugger che per ogni prodotto fa interrogare per recuperare BannedIn, ma dovrebbe essere già recuperato perché ho Includi
Che cosa è necessario ottenere:
In generale dovrebbe essere come 1 query per db e non per ogni riga (x.BannedIn)
Questo è un problema noto (cosiddetto N + 1 query) con sottoquery correlate nelle versioni EF Core precedenti 2.1. È stato corretto in 2.1 - vedi Nuove funzionalità in EF Core 2.1 - Ottimizzazione delle subquery correlate :
Abbiamo migliorato la nostra traduzione di query per evitare l'esecuzione di query SQL "N + 1" in molti scenari comuni in cui l'utilizzo di una proprietà di navigazione nella proiezione porta a unire i dati dalla query radice con i dati di una sottoquery correlata. L'ottimizzazione richiede il buffering dei risultati dalla subquery e richiediamo che tu modifichi la query per attivare il nuovo comportamento.
Quindi, se possibile, eseguire l'aggiornamento agli ultimi bit di EF Core e quindi "opt-in" per l'ottimizzazione aggiungendo .ToList()
alla subquery correlata come spiegato nel collegamento alla documentazione:
BannedIn = x.BannedIn.Select(b => b.CountryId).ToList(),
Il risultato sarà l'esecuzione di 2 query SQL (questo è il modo in cui EF Core funziona con raccolte correlate - 1 query SQL per raccolta), ma non 1 per ogni prodotto come attualmente.