Search code examples
c#entity-framework-corelazy-loading

Detect lazy-load in Entity Framework Core


Entity Framework Core 3.1.2 - I have enabled UseLazyLoadingProxies on my DbContext to ensure data integrity, but I want to throw an exception during development if it is used.

How can I execute some code every time EF Core loads a relationship lazily?


Solution

  • The only way I know is diagnostic messages. See an example here: https://www.domstamand.com/getting-feedback-from-entityframework-core-through-diagnostics.

    The event class you want is https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.diagnostics.lazyloadingeventdata.

    In the application's DBContext

    #if DEBUG
        static ApplicationDbContext()
        {
            // In DEBUG mode we throw an InvalidOperationException
            // when the app tries to lazy load data.
            // In production we just let it happen, for data
            // consistency reasons.
            DiagnosticListener.AllListeners.Subscribe(new DbContextDiagnosticObserver());
        }
    #endif
    

    Then a class to hook into EF notifications

    internal class DbContextDiagnosticObserver : IObserver<DiagnosticListener>
        {
            private readonly DbContextLazyLoadObserver LazyLoadObserver =
                new DbContextLazyLoadObserver();
    
            public void OnCompleted() { }
    
            public void OnError(Exception error) { }
    
            public void OnNext(DiagnosticListener listener)
            {
                if (listener.Name == DbLoggerCategory.Name)
                    listener.Subscribe(LazyLoadObserver);
            }
        }
    

    And then finally the class that throws exceptions whenever a lazy load occurrs

    internal class DbContextLazyLoadObserver : IObserver<KeyValuePair<string, object>>
        {
            public void OnCompleted() { }
            public void OnError(Exception error) { }
    
            public void OnNext(KeyValuePair<string, object> @event)
            {
                // If we see some Lazy Loading, it means the developer needs to
                // fix their code!
                if (@event.Key.Contains("LazyLoading"))
                    throw new InvalidOperationException(@event.Value.ToString());
            }
        }