我创建了一个PhoneBook风格的应用程序;在我的电话簿对象上,我有一个本地成员_site
,用作过滤器,因为大约有1000个电话号码,分布在我的组织内的12个站点上。使用此方法一次只能检索一个站点。
这是我原来的方法。 GUI有几种重新排序数据的方法,所以我把它留作IQueryable,因为我想推迟SQL以允许在SQL服务器上而不是在客户端PC上进行过滤。
作品
public IQueryable<PhoneNumber> GetPhoneDirectory()
{
PhoneBookDataContext db = new PhoneBookDataContext())
return db.PhoneNumbers.Where(d => d.Site == _site);
}
但是,我也试图在using
陈述方面保持“最佳实践”。
不起作用
public IQueryable<PhoneNumber> GetPhoneDirectory()
{
using (PhoneBookDataContext db = new PhoneBookDataContext())
{
return db.PhoneNumbers.Where(d => d.Site == _site);
}
}
现在正如@justanotheruseryoumay所指出的那样,这将导致异常,因为datacontext是在访问对象时被处置的。
我想我要问的是,当我不能使用'using'语句并且不完全知道上下文何时完成时,如何确保我的数据上下文处理得很好。
答案 0 :(得分:5)
如果你想返回IQueryable
,你可以让你的班级包含GetPhoneDirectory
一次性,将PhoneBookDataContext
作为一个字段,并将其处理在你的处置方法中。
然后,您将把责任放在调用者身上以处理他的班级实例。
E.g。
public class MyClass : IDisposable
{
PhoneBookDataContext db;
public MyClass()
{
db = new PhoneBookDataContext();
}
public IQueryable<PhoneNumber> GetPhoneDirectory()
{
return db.PhoneNumbers.Where(d => d.Site == _site);
}
public void Dispose()
{
if (db != null)
{
db.Dispose();
db = null;
}
}
}
// Caller
using(var myClass = new MyClass())
{
var queryable = myClass.GetPhoneDirectory();
...
}
答案 1 :(得分:0)
查询的执行仍将延迟,并且PhoneBookDataContext仍将正确处理,因为使用被编译为try / finally解释。当您实际执行查询时,它将导致运行时错误,因为PhoneBookDataContext不再存在。我建议在你的查询上做一个.ToList()并以这种方式返回它。如果您想在退货后更改订单,那么您仍然可以随意执行LINQ。
修改强> 您可以做的另一件事是在调用方法中使用PhoneBookDataContext创建使用并传入上下文。无论如何,上下文实际上将用于该方法,只要您需要它就可以保留它并坚持使用良好的格式。
答案 2 :(得分:0)
是;这是糟糕的设计,因为只有当您调用导致其被评估的方法(例如IQueryable<PhoneNumber>
或使用ToList()
进行迭代时)才会评估foreach
。
在您的代码中,您将返回尚未评估的IQueryable<PhoneNumber>
,并且在调用者有机会执行它之前,它的内部负责向您发出记录(db);已被处置。
正如建议一样:
public IEnumerable<PhoneNumber> GetPhoneDirectory()
{
using (PhoneBookDataContext db = new PhoneBookDataContext())
{
return db.PhoneNumbers.Where(d => d.Site == _site).ToList();
}
}
或者将db对象重新定位到设计中的其他位置(工作单元和存储库是很好的模式,以便查看IMHO)。