2

我正在构建一个 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 将遍历结果。我发现我总是收到错误“数据上下文导致读取器关闭时调用读取无效”,因为我将数据上下文使用包装在使用范围内。如果我不在 using 子句中列出所有内容,它就可以正常工作。为什么是这样?

认为这不一定是 linq 或 mvc 的事情(但不确定),是 using 子句导致在所有对象返回之前调用 dispose 吗?或者也许 select 子句仅在枚举器被迭代时执行,类似于 yield 的工作方式?

4

2 回答 2

3

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

于 2009-12-24T20:14:37.240 回答
1

使用持续用于方法的调用,所以如果你有这个:

var objects = ListObjects(123);

然后 DataContext 已创建并释放,但尚未返回任何结果。

当您开始枚举结果时:

foreach(var o in objects)

方法表达式树开始执行查询,但数据上下文已被释放,因此无法打开新连接。

这样的事情会起作用,但它会阻止从 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 这样做是安全的。

于 2009-12-24T20:15:41.233 回答