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
。
我有一个具有以下模型和上下文的示例应用程序-
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
。