我正在使用实体框架,偶尔我会得到这个错误。
EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...
即使我没有做任何手动连接管理。
此错误间歇性地发生。
触发错误的代码(为方便阅读而缩短):
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
使用Dispose模式以便每次都打开新的连接。
using (_tEntitites = new TEntities(GetEntityConnection())) {
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
}
仍然有问题
为什么EF不重用一个连接,如果它已经打开。
或者使用MARS (MultipleActiveResultSets),你可以写你的代码,这样你就不会打开多个结果集。
您所能做的就是将数据检索到内存中,这样就不会打开读取器。
它通常是由于在尝试打开另一个结果集时遍历一个结果集而引起的。
示例代码:
public class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogID { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int PostID { get; set; }
public virtual Blog Blog { get; set; }
public string Text { get; set; }
}
假设你在你的数据库中做一个查找,包含这些:
var context = new MyContext();
//here we have one resultset
var largeBlogs = context.Blogs.Where(b => b.Posts.Count > 5);
foreach (var blog in largeBlogs) //we use the result set here
{
//here we try to get another result set while we are still reading the above set.
var postsWithImportantText = blog.Posts.Where(p=>p.Text.Contains("Important Text"));
}
我们可以通过添加.ToList()来解决这个问题,就像这样:
var largeBlogs = context.Blogs.Where(b => b.Posts.Count > 5).ToList();
这迫使entityframework将列表加载到内存中,因此当我们在foreach循环中遍历它时,它不再使用数据读取器来打开列表,而是在内存中。
我意识到,如果你想偷懒加载一些属性,这可能不是你想要的。
这主要是一个示例,希望解释您如何/为什么会遇到这个问题,这样您就可以做出相应的决定
如果我们试图将部分条件分组到Func<>或扩展方法中,我们将得到这个错误,假设我们有这样的代码:
public static Func<PriceList, bool> IsCurrent()
{
return p => (p.ValidFrom == null || p.ValidFrom <= DateTime.Now) &&
(p.ValidTo == null || p.ValidTo >= DateTime.Now);
}
Or
public static IEnumerable<PriceList> IsCurrent(this IEnumerable<PriceList> prices) { .... }
这将抛出异常,如果我们试图在Where()中使用它,我们应该做的是构建一个这样的Predicate:
public static Expression<Func<PriceList, bool>> IsCurrent()
{
return p => (p.ValidFrom == null || p.ValidFrom <= DateTime.Now) &&
(p.ValidTo == null || p.ValidTo >= DateTime.Now);
}
更多信息请访问:http://www.albahari.com/nutshell/predicatebuilder.aspx