.net 处理datacontext会导致在读取器关闭时调用Read的尝试无效

.net 处理datacontext会导致在读取器关闭时调用Read的尝试无效,.net,asp.net-mvc,linq-to-sql,using,using-statement,.net,Asp.net Mvc,Linq To Sql,Using,Using Statement,我正在构建一个MVC2应用程序,并在存储过程中使用LINQtoSQL 我创建了一个数据访问层,它有一个内部datacontext类和一个公开应用程序的公共类。在我的公共类中,我公开了访问datacontext类并使用linq将数据转换为我自己的对象模型类的方法 在我的公共类中,我将使用以下模式公开一个方法: public IEnumerable<MyObject> ListObjects(int iParameter) { using (MyDataContext db =

我正在构建一个MVC2应用程序,并在存储过程中使用LINQtoSQL

我创建了一个数据访问层,它有一个内部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
            };
    } 
} 
public IEnumerable列表对象(int-iPareter)
{
使用(MyDataContext db=new MyDataContext)
{
//调用存储过程并将结果转换为我的对象模型
返回db.List_Objects()。选择(o=>newmyobject())
{
内径=外径,
名称=o.名称
Text=o.代码+“”+o.说明
};
} 
} 
我的MVC应用程序将从一个模型类调用此方法,aspx将遍历结果。我发现我总是收到一个错误“datacontext导致在阅读器关闭时调用Read的尝试无效”因为我将我的数据上下文用法包装在一个using范围内。如果我不将所有内容都保存在using子句中,它就可以正常工作。为什么


我认为这不一定是linq或mvc(但不确定),using子句是否导致在返回所有对象之前调用dispose?或者可能select子句仅在枚举器进行迭代时执行,这与yield的工作原理类似?

Linq to Sql使用工作单元模式封装对数据库的访问,而dispose(使用范围结束)会将访问封装起来关闭与数据库的连接,当您不包装语句时,该连接起作用的原因是枚举查询时上下文仍然处于活动状态(这可能是错误的,因为它可能导致连接保持打开状态),它会抛出,因为只有在您第一次使用
IEnumerable
时才会执行,而这可能就在视图的某个位置,您需要做的是使用
ToList()将
IEnumerable
转换为列表
它将立即强制执行,而不是延迟执行,因此连接将关闭,您将拥有您的收藏。

方法的调用将持续使用,因此如果您有以下情况:

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;
}
public IEnumerable列表对象(int-iPareter)
{
列出对象;
使用(MyDataContext db=new MyDataContext())
{
//调用存储过程并将结果转换为我的对象模型
objects=(db.List_objects()。选择(o=>newmyobject())
{
内径=外径,
名称=o.名称
Text=o.代码+“”+o.说明
}).ToList();
} 
归还物品;
}

如果您了解何时处置上下文,并且可以不处置上下文,那么在我看来,这样做是安全的。

如果您没有将上下文封装在使用模式中,则连接不会保持打开状态。只有手动打开连接时,这才是正确的。处置所做的另一件事是清除更改/添加/删除的对象(datacontext的更改跟踪)。因此,建议通过在using子句中包装datacontext并返回列表来调用dispose,还是完全可以接受假设垃圾收集在超出范围时将其丢弃?实际上,在某些情况下,您可以看到我在执行创建/更新/删除时使用using模式,因为这样代码是隔离的,并且不会返回任何对象或列表,因此您永远不会遇到对象处理问题。对于select查询,我相信GC会清理连接。这对我来说是最重要的。select查询的更改跟踪表非常轻量级(实际上它是空的)。