Question:
I have a asp.net application using entity framework. I have these two models:For that purpose I have this:
The issue is that as soon as I exit my “using” block, all the related adress objects only consist of this error:
How do I still get to access the adresses of my customers, even though I exited the Dbcontext, so I can return them to a view
Answer:
My general advice when working with EF is that entities shouldn’t be referenced outside of the scope of their DbContext. You certainly can work with detached entities, but you have to respect that they are provided in an “as-is” state from the moment they leave the scope of the DbContext. For that reason I recommend that anything passed outside of the scope of the DbContext should be a POCO ViewModel or DTO class to avoid confusing whether an entity class is actually a functional, attached entity representing data domain state, or a detached shell.Option 1: Deal with DTO/ViewModels.
ProjectTo<CustomerDTO>(config)
to replace the use of Select()
above.When leveraging projection, you do not need lazy loading proxies at all. This has arguably become the defacto recommended approach for EF.
The advantages of the projection method are that these DTOs (or ViewModels) cannot be confused with being entities. The issue with detached entities is that where you have methods in your code that might accept entities, these methods might expect to get entities and access members that aren’t loaded. If they are attached and within the scope of a DbContext, those members can be lazy-loaded (not ideal for performance reasons, but functional) however if they are detached you get errors or NullRefExceptions. The other advantage of projection is the payload of data being pulled from the database and sent to the view logic or end consists of just the data needed.
Option 2: Don’t de-scope the DbContext. With projects like ASP.Net MVC web applications, you can leverage an IoC Container to provide dependency injection into your Controllers. In this way you can set up the DbContext to be injected into the constructor with a lifetime scope set to the Request. In this way, for any given request, all services/classes you might call can be managed by the container and have access to the DbContext.
Option 3: Eager load everything you’re going to need to reference. The example you provided should actually work, but your real code is likely missing an eager-load (
.Include()
) for the desired relationship given your example doesn’t attempt to do anything with the Customers collection you load.If your code does:
Include(c => c.Address)
, then it would fail with that error.With EF Core if you are going to want to return entities outside of the scope of a DbContext and you have lazy loading proxies enabled, you will want to temporarily turn off the proxy creation to avoid proxy errors. In this case anything you don’t eager load will be left #null or default.
If you have better answer, please add a comment about this, thank you!