EntityFramework 4.5 - 即使使用了Include仍然会出现ObjectDisposedException异常

5
我遇到了一个异常:ObjectContext实例已被处理并且不再能用于需要连接的操作,即使我已经使用Include方法。

这里是检索实体的函数:

    public List<Entity.CapacityGrid> SelectByFormula(string strFormula, int iVersionId)
    {
        // declaration
        List<Entity.CapacityGrid> oList;

        // retrieve ingredients
        oList = (from Grid in _Dc.CapacityGrid.Include("EquipmentSection")
                             join Header in _Dc.CapacityHeader
                             on Grid.HeaderId equals Header.HeaderId
                             where Header.Formula == strFormula
                             && Header.VersionId == iVersionId
                             select Grid).ToList();

        // return
        return oList;

这里是函数的使用方法:
        // retrieve ingredient quantity by equipement
        using (Model.CapacityGrid oModel = new Model.CapacityGrid(Configuration.RemoteDatabase))
            oQuantity = oModel.SelectByFormula(strFormulaName, iVersionId);

        // code to throw the exception
        var o = (oQuantity[0].EquipmentSection.TypeId);

我知道使用using会关闭连接。我认为ToList()方法会在关闭连接之前实例化包含的对象及其相关对象。

有人能指出我错在哪里吗? 抱歉,我的问题没表述清楚。我明白将抛出异常的代码放在using语句块中是有效的,但我不明白为什么include语句不起作用?

谢谢!


1
尝试在 ToList 前加上 .Include,像这样:.Include(g => g.Equipmentsection).ToList() - DavidG
你好DavidG,不知怎么的,没有include函数。我写了这行代码,但是我收到了这个消息:System.Linq.IQueryable<Entity.CapacityGrid>'不包含 'Include' 的定义,并且没有接受类型为第一参数的扩展方法 'Include' 。谢谢! - Tom Sawyer
@SebastienDErrico:你是否已经包含了System.Data.Entity命名空间?这是Include扩展方法所在的位置。 - gretro
你是对的gretro,我错过了使用System.Data.Entity。 - Tom Sawyer
谢谢大家,include 工作了。把 include 放在 from 里面(在我的情况下会抛出异常)和把 include 放在 ToList 之前有什么区别呢?放在 ToList 之前一切正常。 - Tom Sawyer
显示剩余2条评论
2个回答

3

尝试更改

    // retrieve ingredient quantity by equipement
    using (Model.CapacityGrid oModel = new Model.CapacityGrid(Configuration.RemoteDatabase))
   {  // <-- **add these**
        oQuantity = oModel.SelectByFormula(strFormulaName, iVersionId);

    // code to throw the exception
    var o = (oQuantity[0].EquipmentSection.TypeId);
   } // <-- **add these**

参考:http://msdn.microsoft.com/en-us/library/yh598w02.aspx

如果没有用 {} 包含 using,那么连接会在第一行执行完后就被释放。因为 Entity framework 使用表达式树(这意味着请求直到真正需要它才会执行),你的查询会在 var o = (oQuantity[0].EquipmentSection.TypeId); 处发生。


在 using 语句中也应该放置 oQuantity。 - Aelphaeis
如何避免出现“ObjectContext 实例已被处理并且不能再用于需要连接的操作”错误。该对象正在被处理-使用适当的大括号将代码封装起来可以消除这个问题。 - Nyra
不,问题在于Include为什么没有像它显然应该做的那样去执行。而不是如何修复它。 - Gert Arnold
1
在问题中,我看不出这不是答案-请详细说明。对象oModel被处理掉了-一旦它被处理掉,尝试对其进行任何操作都会抛出异常。将其包装在大括号中将消除该问题,如果.Include()仍然存在问题,它们将是新的-并且是另一个问题。我有什么遗漏吗? - Nyra
我确实理解将抛出异常的行放在using的括号内是有效的,但我不明白为什么include不起作用? - Tom Sawyer
显示剩余3条评论

1
你的问题有三种解决方案。这些来自于此处,是链接到相关实体的三种方法。第一种解决方案是懒加载解决方案,你一直在使用它。只需修改你的代码为此,它就会起作用。之所以会抛出异常是因为懒加载仅在需要时才会发生。当你只需要在少数实体上加载相关实体时,这是一个很好的解决方案。
// retrieve ingredient quantity by equipement
using (Model.CapacityGrid oModel = new Model.CapacityGrid(Configuration.RemoteDatabase))
{
    oQuantity = oModel.SelectByFormula(strFormulaName, iVersionId);

    // Lazy-load occurs here, so it needs to have access to the
    // context, hence why it is in the using statement.
    var o = (oQuantity.First().EquipmentSection.TypeId);
}

第二种解决方案是使用急加载(由@DavidG建议)。因为你只需要加载找到的第一个实体的相关实体,所以我不建议在你的情况下使用它,因为它会加载所有oQuantity实体的EquipmentSection实体。在你的SelectByFormula方法中,使用Include语句,如相关链接所示,它将在第一次调用时加载它(它不会重复访问数据库,但它会一次性拉取更多数据)。

第三种解决方案是避免依赖懒加载,可能是一个好的选择。这是显式加载技术,它将要求你指定你想要在指定的实体上加载EquipmentSection相关实体。

我希望这些解释能帮助你。

另外,你可能希望在你的SelectByFormula方法中返回IQueryable。这样,如果你必须过滤请求,比如使用First()方法仅获取第一个出现的实例,你不会仅仅为一个实例拉取所有内容。


很好的回答,但我不同意你不使用急切加载的说法。在大多数情况下,懒加载并没有给你带来任何额外的好处,事实上可能会使你的应用程序变得更慢。无论如何,我给你点赞。 - DavidG
我的回答不够清晰。我指出我在这种情况下不会使用它,因为他加载了与公式对应的所有实体,然后只取第一项相关实体的值。在这种情况下,急切加载可能会加载比惰性加载或显式加载更多的数据。我已经修正了回答。 - gretro
将System.Data.Entity添加进来,并像链接中所示,将include移动到.ToList之前,这样就解决了我的问题,而不需要移动using子句的括号。谢谢! - Tom Sawyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接