6

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.

10

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?

  • 3
    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 '17 at 18:38
  • @Becuzz: The DbContext is responsible for managing its own lifetime. My suggestion is to let it do that; it will work whether you're using IQueryable or IEnumerable. The most obvious use case that I can think of for lazy loading is where you return some ViewModel object with a related collection in it, but the collection is never used (or only partially used). IQueryable allows you to avoid the cost of retrieving unused records. – Robert Harvey Oct 24 '17 at 18:42
  • 2
    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 '17 at 18:50
  • 3
    @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. – CodingYoshi Oct 25 '17 at 1:34
  • 5
    @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. – CodingYoshi Oct 25 '17 at 1:46
-2

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
    Yes, because business logic is more maintainable when it tightly coupled to data access... :( – TheCatWhisperer Oct 24 '17 at 21:32
-2

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;
}
  • 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? – Kasper van den Berg Oct 1 '18 at 14:31

protected by gnat Sep 28 '18 at 14:30

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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