Question

The current retrieval pattern in my Service classes (in an ASP.NET MVC application) looks something like:

public Client Get(int id)
{
    using (var repo = _repoFactory.Get<Client>())
    {
        return repo.Get(id);
    }
}

Where _repoFactory.Get<T>() returns a repository which, when disposed, also disposes the Entity Framework DbContext;

However, when the consumer of the Get(int id) method needs to use navigation properties on the Client object, an exception is thrown because the context is already disposed.

I can foresee a few ways to negotiate this problem:

  • Don't use navigation properties outside of the service
  • Don't use lazy-loading navigation properties
  • Find some other way to dispose of the context when the request is finished

What is the "correct" (or least incorrect) way and how can it be accomplished?

Was it helpful?

Solution

All the ways that you suggested are "correct," and each has its advantages and disadvantages. You'll need to decide which approach you want to use.

Don't use navigation properties outside of the service

This is difficult to enforce if the service is returning entities. In my current project, we make heavy use of "DTO"s, which are new classes that represent the data that we expect to need in a given context. Because these aren't entities, we know that any property on them will be fully hydrated before it is returned from the repository.

Don't use lazy-loading navigation properties

This is roughly the same as above, except that you're allowing for the possibility of certain navigation properties to be eager-loaded. Again, how does the developer consuming this data know which properties are and are not going to be available? "DTO"s solve this problem, but they also introduce a bunch of extra classes that are almost identical to the existing entities.

Find some other way to dispose of the context when the request is finished

Usually people do this by having contexts bound in a per-request scope in their DI framework, and allow the DI framework to take care of instantiation/disposal of their contexts.

The main danger with this approach is that, while lazy-loading properties won't throw exceptions when accessed, each access requires another database round-trip. This makes it easy for developers to accidentally write code that ends up making thousands of round-trips when only two or three would be required otherwise.

However, if you have a reliable way of identifying performance issues and addressing them, then you could use this approach in the general case and then add a little eager-loading where you find it to be necessary. For example, MiniProfiler can sit on your front-end and give you information about the database round-trips you're making, as well as warnings when it notices that many database queries are practically identical.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top