我正在构建一个MVC 2应用程序,并将linq用于存储过程的sql。
我创建了一个数据访问层,它有一个内部datacontext类和一个公开应用程序的公共类。在我的公共类中,我公开了访问datacontext类的方法,并使用linq将数据转换为我自己的对象模型类。
在我的公共课中,我将使用以下模式公开一个方法:
public IEnumerable<MyObject> ListObjects(int iParameter)
{
using (MyDataContext db = new MyDataContext)
{
//call stored proc and convert results to my object model
return db.List_Objects().Select(o => new MyObject()
{
ID = o.ID,
Name = o.Name
Text = o.Code + " " + o.Description
};
}
}
我的MVC应用程序将从模型类调用此方法,并且aspx将遍历结果。我发现我总是得到一个错误“datacontext导致无效尝试在读取器关闭时调用Read”因为我将数据上下文使用包装在一个使用范围内。如果我不使用using子句中的所有内容,它可以正常工作。这是为什么?
我认为这不一定是linq或mvc的东西(但不确定),是否导致在返回所有对象之前调用dispose的using子句?或者也许select子句只是在枚举器通过类似于yield的工作方式进行迭代时执行?
答案 0 :(得分:3)
Linq to Sql使用工作单元模式来封装对配置的数据库的访问(使用范围的结束)关闭与数据库的连接,当你不包装语句时它工作的原因是上下文仍然存在当冒充查询时(由于它可能会导致连接保持打开状态可能会很糟糕),它会抛出,因为执行只会在您第一次使用IEnumerable
时发生,而IEnumerable
可能位于某个地方,直到视图为止,您需要做的是使用ToList()
将{{1}}转换为列表,这将立即强制执行,而不是延迟执行,以便连接关闭,您将拥有自己的收藏。
答案 1 :(得分:1)
使用会持续调用方法,所以如果你有这个:
var objects = ListObjects(123);
然后创建并处理了DataContext,但尚未返回任何结果。
当你开始枚举结果时:
foreach(var o in objects)
方法表达式树开始执行查询,但是已经处理了datacontext,因此无法打开新连接。
这样的东西可行,但它阻止了从外部ListObjects“扩展”查询的能力。
public IEnumerable<MyObject> ListObjects(int iParameter)
{
List<MyObject> objects;
using (MyDataContext db = new MyDataContext())
{
//call stored proc and convert results to my object model
objects = (db.List_Objects().Select(o => new MyObject()
{
ID = o.ID,
Name = o.Name
Text = o.Code + " " + o.Description
}).ToList();
}
return objects;
}
如果您了解何时处理上下文,并且何时可以不这样做,那么IMO是安全的。