实体框架运行时错误 - 已经有一个打开的 DataReader 与此命令关联,必须先关闭

Posted

技术标签:

【中文标题】实体框架运行时错误 - 已经有一个打开的 DataReader 与此命令关联,必须先关闭【英文标题】:Entity Framework runtime error - There is already an open DataReader associated with this Command which must be closed first 【发布时间】:2020-09-29 12:39:58 【问题描述】:

我有一个包含以下模型和上下文的示例应用程序-

   public class Department
   
     public int Id  get; set; 
     public string Name  get; set;
     public virtual ICollection<Student> Students  get; set; 
   

   public class Student
   
     public int Id  get; set; 

     public string Name  get; set; 

     public virtual Department Department  get; set; 
   
 public class TestContext : DbContext

    public DbSet<Student> Students  get; set; 
    public DbSet<Department> Departments  get; set; 

下面是 progarm.cs 代码。当我调试并且调试器到达 - foreach 块内的 Consol.WriteLine 方法时,我收到错误 - 已经有一个打开的 DataReader 与此命令关联,必须先关闭。这是为什么。到达 foreach 代码时,一旦打开连接,上下文不应自动关闭。

    class Program

    static void Main(string[] args)
    
        using (var context = new TestContext())
        
            var students = context.Students.Where(s => s.Id == 1);

            foreach (var student in students)
            
                Console.WriteLine("Student : 0 - Department 1", student.Name, student.Department.Name);
            

            Console.ReadLine(); 
        
    

【问题讨论】:

这能回答你的问题吗? There is already an open DataReader associated with this Command which must be closed first @marsze - 是的。 【参考方案1】:

为了回答您的问题,您将TestContext 包裹在using 语句中,这意味着TestContext 将保持打开状态直到using 语句结束。

您的初始调用本质上是一个查询,只有在您的 foreach 循环被命中时才会执行:

var students = context.Students.Where(s => s.Id == 1);

这是导致错误的原因。即,它会导致对 DataReader 的多个查询不允许这样做。

@Arman 是正确的:.ToList() 将解决您的问题,因为正在执行查询以在 foreach 循环之前将所有学生都放到一个列表中。显然,这个问题有很多解决方案。可能最常见的是在您的连接字符串上将MARS (Multiple Active Result Sets) 设置为true;即:

Server=myServer;Initial Context=myDb;MultipleActiveResultSets=True;…

这将允许多个打开DataReaders

【讨论】:

【参考方案2】:

由于在 foreach 循环中出现此问题:student.Department.Name

实际上,这里有一个与 foreach 循环关联的 DataReader 和一个与加载 Department 关联的 DataReader

以这种方式更改检索,您的问题应该得到解决:

var students = context.Students.Where(s => s.Id == 1).Include(s => s.Department).ToList();

【讨论】:

使用添加的包含,您可能不需要显式调用ToList

以上是关于实体框架运行时错误 - 已经有一个打开的 DataReader 与此命令关联,必须先关闭的主要内容,如果未能解决你的问题,请参考以下文章

实体框架运行转换代码时引发异常

代码优先实体框架。急切加载,验证然后保存导致错误

实体框架 - MySQL - 未知异常

在 iOS 中对来自 Core Data 的实体的 NSArray 进行快速枚举时出现运行时错误

如何解决实体框架打开 DataReader 问题

更新存储过程实体框架抛出“验证FunctionImport名称是唯一的”错误