Disposing datacontext causes Invalid attempt to call Read when reader is closed

白昼怎懂夜的黑 提交于 2019-12-24 03:42:57

问题


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?


回答1:


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 the IEnumerable to a list using ToList() which will force execution immediately instead of delaying it so the connection will close and you will have your collection.




回答2:


The using lasts for the invocation of the method, so if you have this:

var objects = ListObjects(123);

Then the DataContext has been created and disposed, but no results have been returned yet.

When you start enumerating results:

foreach(var o in objects)

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.

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;
}

If you understand when to dispose the context, and when it's OK not to, it's safe to do so IMO.



来源:https://stackoverflow.com/questions/1959592/disposing-datacontext-causes-invalid-attempt-to-call-read-when-reader-is-closed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!