Lazy Loading

Eintrag zuletzt aktualisiert am: 13.11.2023

Lazy Loading ist eine Optimierungstechnik, die hauptsächlich in bei Webanwendungen und bei Objekt-Relationalen Mappern verwendet wird.

Lazy Loading bei Webanwendungen

Im Webentwicklungskontext bezieht sich Lazy Loading auf das Verzögern des Ladens von Ressourcen wie Bildern, Skripten oder anderen Dateien, bis der Benutzer sie tatsächlich benötigt oder auf sie zugreift. Dies kann die Ladezeiten von Webseiten erheblich verbessern, insbesondere wenn die Seite viele Ressourcen enthält, die nicht sofort sichtbar oder erforderlich sind.

Lazy Loading beim Objekt-Relationalen Mapping

Beim Objekt-Relationalen Mapping bezieht sich Lazy Loading auf das Nachladen verbundener Datensätze, wenn diese benötigt werden. In vielen Objekt-Relationalen Mapping wie z.B. Entity Framework und Entity Framework Core bedeutet Lazy Loading das automatische Nachladen bei Bedarf. Eine entscheidende Frage für die Leistungsfähigkeit von ORM ist die Frage, wann verbundene Objekte zu laden sind. Wenn man zu einem Flug sofort alle Buchungen und die dazugehörigen Passagier- und Personendaten lädt, lädt man unter Umständen mehr als wirklich gebraucht wird. Holt man die Daten jedoch nicht, müssen sie beim Zugriff auf eine Objektreferenz nachgeladen werden. Das Nachladen bei Bedarf nennt man Lazy Loading, Deferred Loading oder Delayed Loading im Gegensatz zum Eager Loading (alias Immediate Loading). Lazy Loading ist der Standard in allen ORM-Werkzeugen, Eager Loading kann man auf Ebene einer Datenbankverbindung (alias Datenkontext oder Data Scope) oder einer einzelnen Anfrage steuern.

Lazy Loading beinhaltet eine besondere Herausforderung, denn das ORM-Werkzeug muss jeglichen Zugriff auf alle Objektreferenzen »abfangen«, um hier bei Bedarf die verbundenen Objekte nachladen zu können. Dieses Abfangen erfolgt durch die Verwendung bestimmter Klassen für Einzelreferenzen und Mengenklassen.

Der Einsatz von Lazy Loading mag auf den ersten Blick sehr komfortabel erscheinen, allerdings ist die Gefahr sehr groß, dass man sehr viele SQL-Befehle zum Datenbankmanagementsystem sendet ohne dies auf Anhieb zu erkennen. Der Autor dieses Beitrags wurde schon oft von Kunden zu Performance-Tuning-Einsätzen gerufen, wo sich der falsche Einsatz des Lazy Loading als ein Kernproblem entpuppte. Lazy Loading macht keinen Sinn, wenn man schon vorher weiß, dass alle Datensätze gebraucht werden. Hier sollte man Eager Loading einsetzen.

Lazy Loading darf auf keinen Fall in Verbindung mit Webservices, Web-APIs/REST-APIs, RPC-Diensten und andere Szenarien verwendet werden, bei den die Entitätsobjekte in Datenformate wie SOAP, XML, JSON oder Protocol Buffers serialisiert werden. Die Serializer greifen auf alle Properties eines Entitätsobjekts zu und lösen dabei ein Lazy Loading aus. Somit werden unnötige Objekte nachgeladen und mehr Daten als notwendig übertragen!

Die Wahl zwischen Lazy Loading und Eager Loading ist oft auch die Wahl zwischen Pest und Cholera: Wenn man nicht genau weiß, ob die zusätzlichen Daten benötigt werden oder nicht, dann kann es ungünstig sein, sie direkt zu laden. Es kann aber auch ungünstig sein, sie später nachladen zu müssen. Wichtige Entscheidungskriterien sind:
  • Wie wahrscheinlich ist, dass die Daten benötigt werden?
  • Wie groß ist die Datenmenge?
  • Kann ich überhaupt später die Daten einfach nachladen? (Wenn die Daten zwischenzeitlich serialisiert wurden, ist ein automatisches Nachladen in der Regel nicht mehr möglich!)

Lazy Loading bei Entity Framework und Entity Framework Core

Beim klassischen Entity Framework ist Lazy Loading im Standard aktiv.

Bei Entity Framework Core muss man Lazy Loading selbst erst aktivieren:

1. Lazy Loading via Runtime Proxies
Install-Package Microsoft.EntityFrameworkCore.Proxies

builder.UseLazyLoadingProxies().UseSqlServer(ConnectionString);

Alle Navigationseigenschaften im ganzen Objektmodell müssen virtual sein.

2. Lazy Loading ohne Proxyklassen
  • Die Entitätsklasse muss darauf vorbereitet sein, eine ILazyLoader-Schnittstelle oder ILazyLoader.Load() als Delegate im Konstruktor injiziert zu bekommen. Letztes ist vorzuziehen, da ILazyLoader in der Microsoft.EntityFrameworkCore.dll steckt und damit eine Abhängigkeit des GO-Projekts mit den Entitätsklassen von Entity Framework Core erzwingen würde.
  • In den Navigationseigenschaften muss dann Load() aufgerufen werden.