Proper use of “Using” statement for datacontext

后端 未结 5 523
醉酒成梦
醉酒成梦 2021-02-06 05:08

I’m using Linq to Entities and lately, I found that a lot of folks recommending wrapping the datacontext in a using statement like this:

Using(DataContext db = n         


        
相关标签:
5条回答
  • 2021-02-06 05:45

    As others have mentioned, it's important for the data contexts to be disposed. I won't go into that further.

    I see three possible designs for the class that ensure that the contexts are disposed:

    1. The second solution you provide in which you create a data context within the scope of each method of rCustomer that needs it so that each datacontext is in a using block.
    2. Keep the data context as an instance variable and have rCustomer implement IDisposable so that when rCustomer is disposed you can dispose of it's data context. This means that all rCustomer instances will need to be wrapped in using blocks.
    3. Pass an instance of an existing data context into rCustomer through its constructor. If you do this then rCustomer won't be responsible for disposing of it, the user of the class will. This would allow you to use a single data context across several instances of rCustomer, or with several different classes that need access to the data context. This has advantages (less overhead involved in creating new data contexts) and disadvantages (larger memory footprint as data contexts tend to hold onto quite a lot of memory through caches and the like).

    I honestly think option #1 is a pretty good one, as long as you don't notice it performing too slowly (I'd time/profile it if you think it's causing problems). Due to connection pooling it shouldn't be all that bad. If it is, I'd go with #3 as my next choice. #2 isn't that far behind, but it would likely be a bit awkward and unexpected for other members of your team (if any).

    0 讨论(0)
  • 2021-02-06 05:57

    The DataContext class is wrapped in a Using statement because it implements the IDisposable interface.

    Internal to the DataContext it is using SqlConnection objects and SqlCommand objects. In order to correctly release these connection back to the Sql Connection Pool, they need to be disposed of.

    The garbage collector will eventually do this, but it will take two passes due to the way IDisposable objects are managed.

    It's strongly encouraged that Dispose is called and the Using statement is a nice way to do this.

    Read these links for more indepth explanation:

    http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe/

    http://www.c-sharpcorner.com/UploadFile/DipalChoksi/UnderstandingGarbageCollectioninNETFramework11292005051110AM/UnderstandingGarbageCollectioninNETFramework.aspx

    0 讨论(0)
  • 2021-02-06 06:01

    Considering the code provided I see, you esplicitly use readonly DataContext db = new DataContext(); like a global variable, so you consider to have that object lifetime along with your rCustomer class instance lifetime.

    If this is true, what you can do, instead of rewriting everything, you can implement IDisposable and inside Dispose() code something like

    private void Dispose()
    {
        if(db  != null) 
            db.Dispose();
    }
    

    Hope this helps.

    0 讨论(0)
  • 2021-02-06 06:07

    An alternative would be to make your rCustomer class implement IDisposable, and then in your Dispose method, you can call Dispose on your DataContext if it is not null. However, this just pushes the Disposable pattern out of your rCustomer class, into whatever types are using rCustomer.

    0 讨论(0)
  • 2021-02-06 06:10

    You can implement a Database factory which will cause your DbContext is being reused.

    You can achieve this as follows:

    DatabaseFactory class:

    public class DatabaseFactory : Disposable, IDatabaseFactory
    {
        private YourEntities _dataContext;
        public YourEntities Get()
        {
            return _dataContext ?? (_dataContext = new YourEntities());
        }
        protected override void DisposeCore()
        {
            if (_dataContext != null)
                _dataContext.Dispose();
        }
    }
    

    Excerpt of the Repository base class:

     public abstract class Repository<T> : IRepository<T> where T : class
    {
        private YourEntities _dataContext;
        private readonly IDbSet<T> _dbset;
        protected Repository(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            _dbset = DataContext.Set<T>();
        }
    
        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }
    
        protected YourEntities DataContext
        {
            get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
        }
    

    Your table's repository class:

    public class ApplicationRepository : Repository<YourTable>, IYourTableRepository
    {
        private YourEntities _dataContext;
    
        protected new IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }
    
        public YourTableRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
            DatabaseFactory = databaseFactory;
        }
    
        protected new YourEntities DataContext
        {
            get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); }
        }
    
       }
        public interface IYourTableRepository : IRepository<YourTable>
       {
       }
    }
    

    This works perfectly together with AutoFac constructor injection as well.

    0 讨论(0)
提交回复
热议问题