Why do I need a ToList() to avoid disposed context errors?

牧云@^-^@ 提交于 2019-12-13 12:26:15

问题


I'm writing some code to access a database using EntityFrameWork. The code is:

public IEnumerable<Rows> GetRows(int id)
{
    using (var context = new ApplicationDbContext())
    {
        var repository = new EntityFrameWorkRepository<int, RowEntity>(context);
        //need a ToList() here to prevent disposed dbcontext errors
        return repository.GetRowsFromDb(id).ToList();
    }
}

GetRowsFromDb() uses LINQ to query the database and filter the results using id.

I originally wrote the above method without the ToList() call, but when I tried to access objects in the IEnumerable which was returned, I would get an exception about the dbcontext already being disposed. I don't understand how the above code fixes things, although it does then work. I assume ToList() is deep copying the object and that this perhaps provides the required separation from the context/database, but surely the original object should be usable?


回答1:


The reason you need to call ToList, ToArray, or some other method that enumerates the data returned by EF is that query execution in LINQ is deferred: the data is not processed until you take it explicitly. By the time your method returns the context through which the query data has been obtained is closed (your using block takes care of that happening quickly), causing the exception that you see.

This is done so that the code is not spending time processing the data that you do not need. For example, you could write code that starts reading through the data on the client side, and stops in the middle. If query execution were not deferred, you would have spent time and memory obtaining the "tail" of the query only to throw it away. Deferred execution puts you in control: you decide what data you want to keep as you go, or bring the entire collection to memory based on what you plan to do with the data.




回答2:


If you don't call .ToList() the enumerable will be evaluated after your using clause finishes, and thus the data context will be disposed before evaluating the query.

IMO, you should consider making your repository handle this (by calling .ToList()) as otherwise this issue is representative of an implementation detail leaking out.




回答3:


Without ToList() you only return enumerator not actual collection of objects. The actual objects are fetched when you try to access the collection. But in this case what you need is a context and repository, because you accessing them from the database. But since it's already out of scope of the using clause both are disposed hence the exception.




回答4:


I assume ToList() is deep copying the object

Not exactly - before you call ToList all you have is a query. you don't get the results until you enumerate it or turn it into a concrete collection via ToList, ToArray, etc.

surely the original object should be usable?

Nope - it's been disposed, which is your way of telling the system that the object has done its job and is no longer needed. The fact that you still have an unexecuted query does not keep the context in a usable state.



来源:https://stackoverflow.com/questions/27510430/why-do-i-need-a-tolist-to-avoid-disposed-context-errors

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