正确使用datacontext的“Using”语句

我正在使用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 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 getTopCustomers() { using(DataContext db = new DataContext()) { return db.customers.Take(10); } } //******************************************* //more methods using db //******************************************* } } 

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

谢谢!

埃德加。

您可以实现数据库工厂,这将导致您的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 : IRepository where T : class { private YourEntities _dataContext; private readonly IDbSet _dbset; protected Repository(IDatabaseFactory databaseFactory) { DatabaseFactory = databaseFactory; _dbset = DataContext.Set(); } protected IDatabaseFactory DatabaseFactory { get; private set; } protected YourEntities DataContext { get { return _dataContext ?? (_dataContext = DatabaseFactory.Get()); } } 

您的表的存储库类:

 public class ApplicationRepository : Repository, 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 { } } 

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

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

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

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

希望这可以帮助。

正如其他人所提到的那样,处理数据上下文非常重要。 我不会进一步讨论这个问题。

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

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

老实说,我认为选项#1是一个相当不错的选项,只要你没有注意到它的表现太慢(如果你认为它导致了问题,我会及时/描述它)。 由于连接池,它应该不是那么糟糕。 如果是的话,我会选择#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

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