正确使用datacontext的“Using”语句

时间:2012-04-23 14:01:18

标签: c# entity-framework linq-to-entities

我正在使用Linq to Entities,最近,我发现很多人都建议将datacontext包装在这样的using语句中:

Using(DataContext db = new DataContext) {
    var xx = db.customers;
}

这是有道理的。但是,我不确定如何在我的模型中加入这种做法。 例如:我有一个接口(让我们称之为客户),它由像这样的存储库实现:

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.
        //*******************************************

    }
}

然后,为了利用使用,我需要将方法更改为:

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
        //*******************************************

    }
}

我的问题是:使用“使用”的建议真的那么好吗?请注意这个更改将是一个主要的,我有大约25个接口/存储库组合,每个有大约20-25种方法,更不用说完成后需要重新测试一切。 还有其他方法吗?

谢谢!

埃德加。

5 个答案:

答案 0 :(得分:5)

您可以实施数据库工厂,这将导致 DbContext重用

您可以按如下方式实现:

DatabaseFactory类:

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();
    }
}

Repository基类的摘录:

 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()); }
    }

您的表的存储库类:

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>
   {
   }
}

这也与AutoFac构造函数注入完美结合。

答案 1 :(得分:3)

考虑到我提供的代码,你明确地使用readonly DataContext db = new DataContext();就像一个全局变量,所以你考虑让对象生命周期和你的rCustomer类实例生命周期一起使用。

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

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

希望这有帮助。

答案 2 :(得分:3)

正如其他人所提到的,处理数据上下文非常重要。我不会再深入探讨。

我看到该类有三种可能的设计,可确保上下文处理:

  1. 您提供的第二个解决方案,您在rCustomer的每个方法范围内创建数据上下文,以便每个datacontext位于using块中。
  2. 将数据上下文保留为实例变量,并rCustomer实现IDisposable,以便在处置rCustomer时可以处置它的数据上下文。这意味着所有rCustomer个实例都需要包含在using块中。
  3. 通过其构造函数将现有数据上下文的实例传递到rCustomer。如果你这样做,那么rCustomer将不负责处理它,该类的用户将。这将允许您跨多个rCustomer实例使用单个数据上下文,或者使用需要访问数据上下文的多个不同类。这具有优势(创建新数据上下文所涉及的开销较少)和缺点(较大的内存占用,因为数据上下文通过缓存等容易占用大量内存)。
  4. 老实说,我认为选项#1是一个相当不错的选项,只要你没有注意到它的表现太慢(如果你认为它导致了问题,我会及时/描述它)。由于连接池,它应该不是那么糟糕。如果是的话,我会选择#3作为我的下一个选择。 #2并不落后,但对于你团队的其他成员(如果有的话)来说,这可能会有点尴尬和意外。

答案 3 :(得分: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

答案 4 :(得分:2)

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