Betrachten Sie diese erfundene Entitätsobjekten:Entfernen wählen N + 1 ohne .INCLUDE
public class Consumer
{
public int Id { get; set; }
public string Name { get; set; }
public bool NeedsProcessed { get; set; }
public virtual IList<Purchase> Purchases { get; set; } //virtual so EF can lazy-load
}
public class Purchase
{
public int Id { get; set; }
public decimal TotalCost { get; set; }
public int ConsumerId { get; set; }
}
Lassen Sie uns jetzt sagen, dass ich diesen Code ausführen möchten:
var consumers = Consumers.Where(consumer => consumer.NeedsProcessed);
//assume that ProcessConsumers accesses the Consumer.Purchases property
SomeExternalServiceICannotModify.ProcessConsumers(consumers);
standardmäßig diese von Select N leiden + 1 in der ProcessConsumers-Methode. Es wird eine Abfrage ausgelöst werden, wenn sie die Verbraucher aufzählt, dann wird es jede Einkauf Sammlung 1 von 1. Die Standardlösung für dieses Problem einer Include hinzuzufügen wäre zu greifen:
var consumers = Consumers.Include("Purchases").Where(consumer => consumer.NeedsProcessed);
//assume that ProcessConsumers accesses the Consumer.Purchases property
SomeExternalServiceICannotModify.ProcessConsumers(consumers);
dass in vielen Fällen gut funktioniert, aber in einigen komplexen Fällen kann ein Include die Leistung um Größenordnungen zerstören. Ist es möglich, so etwas zu tun.
- Schnappen meine Verbraucher, var Verbraucher = _entityContext.Consumers.Where (...) ToList()
- meine Einkäufe Schnappen, var Käufe = _entityContext.Purchases. Wo (...). ToList()
- Hydratisieren Sie den Consumer.Purchases Sammlungen manuell von den Einkäufen, die ich bereits in den Speicher geladen. Wenn ich es dann an ProcessConsumers übergebe, wird es nicht mehr Datenbankabfragen auslösen.
Ich bin mir nicht sicher, wie man # 3 macht. Wenn Sie versuchen, auf eine Consumer-Sammlung zuzugreifen, die die Lazy Load (und damit die Select N + 1) auslöst. Vielleicht muss ich die Consumers in den richtigen Typ (anstelle des EF-Proxy-Typs) und laden Sie dann die Sammlung? Etwas wie folgt aus:
foreach (var consumer in Consumers)
{
//since the EF proxy overrides the Purchases property, this doesn't really work, I'm trying to figure out what would
((Consumer)consumer).Purchases = purchases.Where(x => x.ConsumerId = consumer.ConsumerId).ToList();
}
EDIT: Ich habe das Beispiel ein wenig neu geschrieben hoffentlich, um das Problem deutlicher zu offenbaren.
IIRC EF wird automatisch die Sammlungen hydratisieren, so # 3 muss nicht manuell getan werden. – jeroenh
Ihre erste Abfrage sollte als einzelne SQL-Anweisung ausgeführt werden. Sehen Sie mehrere db-Aufrufe? –
@Nicholas, du hast recht, ich habe das Beispiel aktualisiert, um Select N + 1 zu machen. Dies ist ein sehr einfaches erfundenes Beispiel, lies die ganze Frage und versuche zu verstehen, was ich wirklich frage. Tatsächliche Beispiele, bei denen .Include nicht ausreicht, sind dramatisch komplexer und nicht sinnvoll, um eine SO-Frage zu stellen. – manu08