从using块中返回iquerable.需要更好的设计
本文关键字:更好 iquerable using 返回 | 更新日期: 2023-09-27 18:17:48
我创建了一个电话簿样式的应用程序;在我的电话簿对象上,我有一个本地成员_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所指出的,这将导致一个异常,因为在访问对象时数据上下文已经被处理掉了。
我想我要问的是,我怎么能确保我的数据上下文很好地处理,当我不能使用'using'语句,不严格知道上下文何时完成。
如果您想返回IQueryable
,您可以使包含GetPhoneDirectory
的类可丢弃,使PhoneBookDataContext
成为一个字段,并在处置方法中处置它。
然后,您将把责任放在调用者身上,以处置您的类的他的实例。
。
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();
...
}
查询的执行仍然会被延迟,并且PhoneBookDataContext仍然会被正确处置,因为using被编译器解释为try/finally。当您实际执行查询时,它将导致运行时错误,因为PhoneBookDataContext不再存在。我建议在您的查询上做一个。tolist()并以这种方式返回它。如果您想在退货后更改订单,那么您仍然可以根据需要对其进行LINQ处理。
编辑:你可以做的另一件事是在调用方法中使用PhoneBookDataContext创建using,并在上下文中传递。无论如何context都会在那个方法中使用只要你需要它你就可以保留它并坚持使用好的格式。
是;这是一个糟糕的设计,因为你的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对象重新定位到设计中的其他地方(Unit Of Work和Repository是很好的模式,可以看看)。