关闭读取器时,处置数据上下文会导致调用 Read 的尝试无效
我正在构建一个 MVC 2 应用程序并使用 linq to sql 和存储过程。
我创建了一个数据访问层,它具有一个内部数据上下文类和一个公开应用程序的公共类。在我的公共类中,我公开了访问 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 将迭代结果。我发现我总是收到错误“数据上下文导致阅读器关闭时调用 Read 的尝试无效”,因为我将数据上下文使用包装在 using 范围内。如果我不将所有内容都放在 using 子句中,它就可以正常工作。这是为什么呢?
我认为这不一定是 linq 或 mvc 的东西(但不确定),using 子句是否导致在返回所有对象之前调用 dispose?或者也许 select 子句仅在枚举器被迭代时才执行,类似于yield 的工作方式?
I'm building an MVC 2 app and using linq to sql with stored procs.
I created a data access layer that has an internal datacontext class and a public class that I expose applications. In my public class I expose methods which access the datacontext class and convert the data to my own object model classes using linq.
In my public class, I would expose a method using the following patter:
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
};
}
}
My MVC app would call this method from a model class, and the aspx would iterate through the results. I found that I always get an error "datacontext causes Invalid attempt to call Read when reader is closed" because I wrap my data context usage inside a using scope. If I don't scpope everything in a using clause it works fine. Why is this?
I think this is not necessarily a linq or mvc thing (but don't know for sure), is the using clause causing the dispose to be called before all the objects are returned? Or maybe the select clause is only executing as the enumerator is being iterated through similar to how yield works?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Linq to Sql 使用工作单元模式来封装对数据库的访问,该数据库在处置(使用范围结束)时会关闭与数据库的连接,当您不包装语句时它会起作用的原因是枚举时上下文仍然存在查询(这可能很糟糕,因为它可能导致连接保持打开状态),它会抛出,因为只有当您第一次使用 IEnumerable 时才会执行,它可能位于视图中的某处,您需要做的是使用
ToList()
将IEnumerable
转换为列表,这将强制立即执行而不是延迟它,因此连接将关闭,您将获得收藏。Linq to Sql uses the unit of work pattern to encapsulate access to the database which on dispose (end of using scope) closes the connection to the database, the reason it works when you dont wrap the statement is the context is still alive when enumarating the query (which may be bad as it may lead to the connection remaining open), it throws because the execution will only occur when you first use the
IEnumerable
which may be somewhere down the line as far as the view, what you need to do is transform theIEnumerable
to a list usingToList()
which will force execution immediately instead of delaying it so the connection will close and you will have your collection.using 持续到方法的调用,所以如果有这样的情况:
那么 DataContext 已被创建并释放,但尚未返回任何结果。
当您开始枚举结果时:
方法表达式树开始执行查询,但数据上下文已被释放,因此无法打开新连接。
类似这样的方法可以工作,但它阻止了从 ListObjects 外部“扩展”查询的能力。
如果您了解何时处理上下文,何时可以不处理,那么在我看来,这样做是安全的。
The using lasts for the invocation of the method, so if you have this:
Then the DataContext has been created and disposed, but no results have been returned yet.
When you start enumerating results:
The method expression tree starts executing the query, but the datacontext is already disposed, and therefore can't open a new connection.
Something like this will work, but it prevents the ability to 'extend' the query from outside ListObjects.
If you understand when to dispose the context, and when it's OK not to, it's safe to do so IMO.