1

In all the examples I see for Entity Framework data access, every method has its own using block, as shown below.

Is there an alternative to this approach? For example, can the context object just be a class member, such as:

MyModelContext context = new MyModelContext();

Is there a reason why a new context object has to be created for each method in the DAO class?

public class DaoClass
{
    public void DoSomething()
    {
         using (var context = new MyModelContext()) 
         {     
             // Perform data access using the context 
         }
    }

    public void DoAnotherThing()
    {
         using (var context = new MyModelContext()) 
         {     
             // Perform data access using the context 
         }
    }

    public void DoSomethingElse()
    {
         using (var context = new MyModelContext()) 
         {     
             // Perform data access using the context 
         }
    }

}
John Steed
  • 599
  • 1
  • 12
  • 31
  • You could push the responsibility to dispose up to the consumer by instantiating the context as a field during construction, implementing IDisposable on the DaoClass, and making sure all consumers are properly disposing of it. In your current case, each method is responsible for provisioning and disposing of it's resources. – Jonathon Chase Oct 31 '18 at 20:56

3 Answers3

2

You could have the DaoClass implement IDisposable and have the context be a property of the class. Just make sure to wrap DaoClass in a using statement or call Dispose() on the instance of the DaoClass.

public class DaoClass : IDisposable
{
    MyModelContext context = new MyModelContext();

    public void DoSomething()
    {
        // use the context here
    }

    public void DoAnotherThing()
    {
        // use the context here
    }

    public void DoSomethingElse()
    {
        // use the context here
    }

    public void Dispose()
    {
        context.Dispose();
    }
}
Lews Therin
  • 3,707
  • 2
  • 27
  • 53
  • So is the only benefit of the `using` statements in my original post is the disposal of the object? Is that correct? – John Steed Oct 31 '18 at 21:04
  • Correct. `using` statements are just syntactic sugar. It wraps the statement in the parenthesis in a `try...finally` block and calls the object's `Dispose()` method in the `finally` block. See [this answer](https://stackoverflow.com/a/212210/4416750). – Lews Therin Nov 01 '18 at 13:13
1

Please note that the context object is the equivalent to a database transaction.

It implements the IDisposable interface because a transaction must be closed when done with and you either have to use the using statement or make an implementation of IDisposable like Lews Therin demonstrated.

We use multiple instances of a context object to separate different transactions. There will be cases when you want all changes to go as a single transaction and either commit all together or rollback everything. Then you put it all in one context instance. But there will also be cases where you want to separate the saving of one data pack from another. Then you use different transactions, i.e. different context objects.

To get a better grasp of this chapter take a look at the unit of work pattern.

Hope I could help, merry coding!

Kostas Dafnomilis
  • 629
  • 1
  • 5
  • 13
  • Note that while a DbContext instance is intended to support a UnitOfWork, it is a bigger scope than a database transaction. You might fetch data, work on it in memory and finally save it to the database in your UnitOfWork. This would be too long-running for a database transaction. I might be better to describe the scope as a "business transaction". – David Browne - Microsoft Nov 01 '18 at 18:33
0

The way you show it is how I've seen it recommended everywhere. I've seen there be weird issues with class level declaration returning stale or incorrect data.

To get around duplicating all the code I like to write an execute method that I can reuse, or make changes without having to go to every using.

   private T Execute<T>(Func<MyModelContext, T> function)
        {
            using (MyModelContext ctx = new MyModelContext())
            {
                var result = function(ctx);
                ctx.SaveChanges();
                return result;
            }
        }

  public List<Type> GetTypes()
        {
            return Execute((ctx) =>
            {
                return ctx.Types.ToList();
            });
        }
Ryan Schlueter
  • 2,223
  • 2
  • 13
  • 19