18

I'm building a wpf application which implements the following features:

  1. Take user input and read data from databases
  2. perform some calculations on it
  3. Showcase it to the user in multiple types of views and write changes back to db

Proposed architecture: Database -> Entity Framework -> Repository -> Business Logic -> Data Service -> ViewModel

Reasons to use this architecture: Multiple scenarios present in the application (Multiple views) and multiple databases. Hence, i'm willing to use repository in the middle for abstraction.

One caveat is that the context will be long lived if repository is implemented. To overcome this, is it okay to create a context and dispose them in a using() block in each of the crud methods.?

feel free to suggest alternate approaches.

2
  • Have a look at this thread which is similar to your query. stackoverflow.com/questions/21875816/…
    – Gopinath
    Oct 24, 2017 at 17:37
  • The factory pattern is the most straightforward solution to the issue of long-lived injected dependencies that occur in a persistent runtime (e.g. WPF or Windows services). This is not necessary for shortlived runtimes such as a web project as it disposes of everything (or it should) on a per-request basis.
    – Flater
    Jun 9 at 19:00

4 Answers 4

23

Use one DbContext object per data access or transaction.

DbContext is a lightweight object; it is designed to be used once per business transaction. Making your DbContext a Singleton and reusing it throughout the application can cause other problems, like concurrency and memory leak issues.

DbContext essentially implements a Unit of Work. Treat it accordingly.

Don't dispose DbContext objects.

Although the DbContext implements IDisposable, you shouldn't manually dispose it, nor should you wrap it in a using statement. DbContext manages its own lifetime; when your data access request is completed, DbContext will automatically close the database connection for you.

To understand why this is the case, consider what happens when you run a Linq statement on an entity collection from a DbContext. If you return a lazy-loading IQueryable from your data access method, you stand up a pipeline that isn't actually executed until the client compels some data from it (by calling FirstOrDefault(), ToList() or iterating over it).

Further Reading
Do I always have to call Dispose() on my DbContext objects?
Why you shouldn't use Singleton DataContexts in Entity Framework
Returning IEnumerable<T> vs. IQueryable<T>
Should Repositories return IQueryable?

16
  • 6
    While I'm sure someone will come up with some sort of exceptional case for this, I honestly can't come up with a good use case for returning an un-materialized IQueryable from your data access classes. That just gives calling code the capability to reach into your data access (something it probably has no business doing) and muck with things. That being said, is it really that big of a concern to worry about using using blocks? Or am I just not thinking of some case where using an IQueryable as you suggest would be worth the trouble?
    – Becuzz
    Oct 24, 2017 at 18:38
  • 3
    I understand all of that, it's just that I've been burned by having people return IQueryables all over the place. And then something farther up the chain added some includes or other things that made for a horrifically bad query (from a DB performance perspective). And that was a fun bug to track down. As such, I've had opportunity to think about if returning an IQueryable is ever a good idea. And I could never think of a time where it was worth the maintenance trouble. (cont.)
    – Becuzz
    Oct 24, 2017 at 18:50
  • 4
    @RobertHarvey what exactly is the point of a repository layer if it is returning an IQueryable to the client? You are basically giving the client the option to write queries--sure they will not be sql queries but nonetheless they are queries (just written using C#) and it will be all over the place. If a repository is returning IQueryable then you may as well throw away the repository. Oct 25, 2017 at 1:34
  • 12
    @RobertHarvey I disagree with not disposing DbContext and disagree with the referred article. The whole idea is to code against the interface and the interface tells me it is IDisposable. I am not going to write my code based on the inner workings of how the EF team has implemented DbContext or chase the devs on that team--they can change it anytime they want. Neither am I going to ask myself or other developers to start digging into the inner workings of each class to see if IDisposable is really useful. I have worked too hard to get the devs on my team to dispose only to ask them not always. Oct 25, 2017 at 1:46
  • 1
    I am seeing the Microsoft themselves recommend a using statement with DbContext, as seen here. Particularly: "If the context is created in application code, remember to dispose of the context when it is no longer required." I am wondering then what the justification is for not using Dispose or a using statement?
    – pay
    Oct 28, 2019 at 15:12
1

You probably don't need to, but that doesnt mean you should never.

There is a lot of advice, around the internet, and in the top rated post on this page, telling you that you "Must Not" dispose the DB Context.

The logic here is fundamentally flawed. This is a bold statement, so let me explain.

There is a difference between "You don't need to do X" and "You must never do X".

If you create the context, then let the garbage collector take care of it at some undefined time in the future, you aren't going to get memory leaks. This means, essentially, that you "Don't need" to dispose of the context explicitly.

However, this does not logically translate into "Must Never".

If you read the actual MSDN documentation for DbContext you will see that there is a benefit to explicitly disposing the context; it has many resources that it holds, including caches.

Use using if you want all the resources that the context controls to be disposed at the end of the block. When you use using, the compiler automatically creates a try/finally block and calls dispose in the finally block.

If the context is created in application code, remember to dispose of the context when it is no longer required.

https://docs.microsoft.com/en-us/ef/ef6/fundamentals/working-with-dbcontext#lifetime

Leaving the task of disposing that stuff to the garbage collector will slightly increase memory usage - of course, you "Might Not" ever encounter that problem, and will be able to ignore it.

The automatic internal disposal seems to be a safety measure only

Applications doing huge volumes of DB access using a DbContext will have interesting memory usage patterns. Having an understanding of the various modes of garbage collection is important here.

In particular, you need to understand what happens when you hit what Microsoft refer to as "High Memory Usage Percent".

when the physical memory load reaches 90%, garbage collection becomes more aggressive about doing full, compacting garbage collections to avoid paging

This is when the large amount of cached data that you find in as yet undisposed DB context begins to be an issue.

https://docs.microsoft.com/en-us/dotnet/core/runtime-config/garbage-collector#high-memory-percent

Many of Microsoft's own examples of EF usage literally tell you to dispose explicitly

For example, here is a microsoft tutorial (for EF5) of the implementation of a repository.

https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application#creating-the-unit-of-work-class

The code sample here explicitly disposes the context when the repo is disposed.

Make a decision based on the facts

The DbContext is intended to act as a single "unit of work". Its unfortunate that Microsoft chose to hide the fact that they are implementing the unit of work pattern - I believe that's what has led to this confusion.

If your services are doing things like, processing huge volumes of data, you will find that the undisposed resources maintained internally by your DbContext will push you into "high memory percentage" territory. At that point, its worth seeing if explicitly disposing of your DbContext makes a difference. You as the developer know that those resources are no longer needed, whereas the garbage collector does not. That isn't its fault - its a general purpose tool.

-3

Ideally the context should be initialized and terminated for a single transaction. In your case the context should be instantiated in Business Logic and passed on to Repository for data read/write.

1
  • 2
    Yes, because business logic is more maintainable when it tightly coupled to data access... :( Oct 24, 2017 at 21:32
-3

If you call DbContext on each method in your application you will experience memory leak. Use a single instance of the DbContext. See the comment in the bellow example:

public bool IsInStock(int _ProductId)
{
  var result = false;

  try
  {
    using (var dataService = new StoreDbDataService()) // NB: This line on each method will eventually cause memory leak.
    {
      result = dataService.IsInStock(_ProductId);
    }
  }
  catch (Exception ex)
  {
    Log.LogException(ex);
  }

  return result;
}
2
  • 1
    Can you explain why calling DbContext would cause a memory leak? The comment in the source does not help me understand it. I would assume that the using block would cause Dispose to be called on the StoreDBDataService which eventually clean all resources allocated, wouldn't it? Oct 1, 2018 at 14:31
  • This is basically the Ron Swanson "permit" clip but in code.
    – Dagrooms
    Aug 12, 2019 at 20:06

Not the answer you're looking for? Browse other questions tagged or ask your own question.