【问题标题】:Entity Framework exception when looping through entities (works when using ToList( ), though)遍历实体时的实体框架异常(但在使用 ToList( ) 时有效)
【发布时间】:2012-08-08 18:27:29
【问题描述】:

我有一个名为 MyItems 的实体表,该表中的每个项目都有一个指向另一个表的外键。我想简单地遍历我的项目并访问每个项目的外键对象的字符串“名称”属性,如下所示:

foreach (var myItem in (from q in context.MyItems select q))
{
   string testName = myItem.ForeignItem.Name
}

当我这样做时,ForeignItem 为空,当我尝试访问 ForeignItem 时收到 InvalidOperationException:

已经有一个打开的 DataReader 与此命令关联 必须先关闭。

但是 - 如果我改为这样调用 ToList():

(from q in context.MyItems select q).ToList()

我的外键对象填充得很好。我意识到 ToList() 会很昂贵,因为将立即检索整个表。我怀疑延迟加载在幕后出了点问题,但我正在理解它应该在不调用ToList()的情况下工作。

我是否忽略了什么?

编辑:我在想var 的使用可能会导致问题,所以我尝试使用

foreach (MyItem myItem in (from q in context.MyItems select q))
{
   // loop contents
}

相反 - 结果相同。 myItem 的属性已填充,但外键对象除外,它们保持为空。

编辑#2:我在整个应用程序中只使用一个对象上下文和一个 Linq-to-Entities 语句,所以我无法解释另一个 DataReader 在哪里运行.我还应该注意,这个错误发生在循环中的第一个对象上,所以它不是因为检索到前一个项目。

【问题讨论】:

  • ForeignItem.Name 是否需要预先加载?
  • 你试过把 myItem.ForeignItem.Load();在您实际尝试获取 ForeignItem.Name 值之前?
  • @Brian 它应该被加载,期间。为什么当我打电话给ToList() 时它会起作用,但当我不打电话时它不起作用是个大问题。
  • @Jane Doe 即使ForeignItem 公开了这样一个方法,ForeignItem 也是空的,所以我会在空对象上调用实例方法。
  • 所以 myItem.ForeignItem 不会暴露 .Load();或 .LoadForeignItemReference()?

标签: c# entity-framework linq-to-entities lazy-loading


【解决方案1】:

您写的是myItem 而不是q。你应该使用这个:

(from q in context.MyItems select q)

或者更简单地说,你可以这样写:

context.MyItems

关于您更新的问题,这似乎是因为您在第一个查询完成之前启动了一个新查询。可能的解决方案:

  • 在运行原始查询时包含子项。

    foreach (var myItem in context.MyItems.Include("ForeignItem")) { ... }
    
  • 启用 MultipleActiveResultSets。

相关

【讨论】:

  • 我正在为 SO 清理我的对象名称,错字与问题无关。我已经更新了问题中的代码。
  • 不也存在延迟执行的问题吗? IIRC,LINQ 查询推迟执行,直到通过 ToList/ToArray 之类的东西对其进行操作。 ForEach 会强制执行吗?
  • @kevinmajor1 是的,foreach 将强制执行。
  • 感谢您更新您的答案。 Include() 似乎只接受字符串参数。我怀疑该代码不正确。我将尝试使用relevant MSDN article 中指定的类型名称。
【解决方案2】:

这就是我最终做的,根据马克的建议使用Include( )

(from q in context.MyItems.Include("ForeignItemOne").Include("ForeignItemTwo").Include("ForeignItemThree") select q)

顺便说一句,将 MultipleActiveResultSets 设置为 true 也可以。现在,我将使用Include(),因为应用程序很小,并且只有一个 Linq 语句。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多