我正在使用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种方法,更不用说完成后需要重新测试一切。 还有其他方法吗?
谢谢!
埃德加。
答案 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
类实例生命周期一起使用。
如果这是真的,你可以做什么,而不是重写一切,你可以实现IDisposable
和Dispose()
内部代码
private void Dispose()
{
if(db != null)
db.Dispose();
}
希望这有帮助。
答案 2 :(得分:3)
正如其他人所提到的,处理数据上下文非常重要。我不会再深入探讨。
我看到该类有三种可能的设计,可确保上下文处理:
rCustomer
的每个方法范围内创建数据上下文,以便每个datacontext位于using
块中。rCustomer
实现IDisposable,以便在处置rCustomer
时可以处置它的数据上下文。这意味着所有rCustomer
个实例都需要包含在using
块中。rCustomer
。如果你这样做,那么rCustomer
将不负责处理它,该类的用户将。这将允许您跨多个rCustomer
实例使用单个数据上下文,或者使用需要访问数据上下文的多个不同类。这具有优势(创建新数据上下文所涉及的开销较少)和缺点(较大的内存占用,因为数据上下文通过缓存等容易占用大量内存)。老实说,我认为选项#1是一个相当不错的选项,只要你没有注意到它的表现太慢(如果你认为它导致了问题,我会及时/描述它)。由于连接池,它应该不是那么糟糕。如果是的话,我会选择#3作为我的下一个选择。 #2并不落后,但对于你团队的其他成员(如果有的话)来说,这可能会有点尴尬和意外。
答案 3 :(得分:2)
DataContext类包含在Using语句中,因为它实现了IDisposable接口。
DataContext内部使用SqlConnection对象和SqlCommand对象。为了正确地将这些连接释放回Sql连接池,需要将它们丢弃。
垃圾收集器最终将执行此操作,但由于IDisposable对象的管理方式,它将需要两次传递。
强烈建议调用Dispose,使用Using语句是一种很好的方法。
阅读这些链接以获得更深入的解释:
答案 4 :(得分:2)
另一种方法是让你的rCustomer类实现IDisposable,然后在你的Dispose方法中,如果它不是null,你可以调用DataContext上的Dispose。但是,这只会将您的rCustomer类中的Disposable模式推送到使用rCustomer的任何类型。