Entity Framework 运行时错误 - 已经有一个与此命令关联的打开的 DataReader,必须先将其关闭

Entity Framework runtime error - There is already an open DataReader associated with this Command which must be closed first

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

   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(); 
        }
    }

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

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

改变检索方式,您的问题应该得到解决:

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

为了回答您的问题,您将 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