8

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 = new DataContext) {
    var xx = db.customers;
}

This makes sense. However, I’m not sure how to incorporate this practice in my model. For example: I have an interface (let’s call it customer) and it is implemented by a repository like this:

namespace Models
{
    public class rCustomer : iCustomer
    {

        readonly DataContext db = new DataContext();

        public customer getCustomer(Guid id)
        {
            return db.customers.SingleOrDefault(por => por.id == id);
        }

        public iQueryable<customer> getTopCustomers()
        {
            return db.customers.Take(10);
        }

        //*******************************************
        //more methods using db, including add, update, delete, etc.
        //*******************************************

    }
}

Then, to take the advantage of using, I will need to change the methods to look like this:

namespace Models
{
    public class rCustomer : iCustomer
    {
        public customer getCustomer(Guid id)
        {
            using(DataContext db = new DataContext()) {       
                return db.customers.SingleOrDefault(por => por.id == id);
            } 
        }

        public iQueryable<customer> getTopCustomers()
        {
            using(DataContext db = new DataContext()) {       
                 return db.customers.Take(10);
            } 
        }

        //*******************************************
        //more methods using db
        //*******************************************

    }
}

My question is: the recommendation of using “Using” is really that good? Please take in consideration that this change will be a major one, I have about 25 interfaces/repository combos, and each has about 20-25 methods, not to mention the need to re-test everything after finish. Is there other way?

Thanks!

Edgar.

4

5 回答 5

5

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.

于 2012-04-23T14:03:18.730 回答
3

正如其他人所提到的,处理数据上下文很重要。我不会更进一步。

我看到了确保释放上下文的类的三种可能设计:

  1. 您提供的第二个解决方案rCustomer是在需要它的每个方法的范围内创建数据上下文,以便每个数据上下文都在一个using块中。
  2. 将数据上下文保留为实例变量并rCustomer实现 IDisposable 以便在rCustomer处置时可以处置它的数据上下文。这意味着所有rCustomer实例都需要包装在using块中。
  3. rCustomer通过其构造函数传递现有数据上下文的实例。如果您这样做,rCustomer则不负责处理它,该类的用户将负责。rCustomer这将允许您在 的多个实例或需要访问数据上下文的多个不同类中使用单个数据上下文。这具有优点(创建新数据上下文所涉及的开销更少)和缺点(更大的内存占用,因为数据上下文倾向于通过缓存等保留相当多的内存)。

老实说,我认为选项#1 是一个非常好的选项,只要您没有注意到它的执行速度太慢(如果您认为它会导致问题,我会对其进行时间/分析)。由于连接池,它不应该那么糟糕。如果是的话,我会选择#3 作为我的下一个选择。#2 并不落后,但对于团队的其他成员(如果有的话)来说可能会有点尴尬和意外。

于 2012-04-23T14:24:49.540 回答
3

考虑到我看到的提供的代码,您特别readonly DataContext db = new DataContext();像全局变量一样使用,因此您考虑拥有该对象的生命周期以及您的rCustomer类实例的生命周期。

如果这是真的,你可以做什么,而不是重写一切,你可以实现IDisposable和内部Dispose()代码类似

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

希望这可以帮助。

于 2012-04-23T14:06:44.500 回答
2

DataContext 类包含在 Using 语句中,因为它实现了 IDisposable 接口。

在 DataContext 内部,它使用 SqlConnection 对象和 SqlCommand 对象。为了正确地将这些连接释放回 Sql 连接池,它们需要被处理掉。

垃圾收集器最终会执行此操作,但由于 IDisposable 对象的管理方式,它需要两次传递。

强烈建议调用 Dispose 并且 Using 语句是执行此操作的好方法。

阅读这些链接以获得更深入的解释:

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

于 2012-04-23T14:06:16.283 回答
2

另一种方法是让您的 rCustomer 类实现IDisposable,然后在您的Dispose方法中,如果它不为空,您可以在 DataContext 上调用 Dispose 。但是,这只是将 Disposable 模式从您的 rCustomer 类中推出到使用 rCustomer 的任何类型中。

于 2012-04-23T14:08:13.410 回答