我正在使用实体框架,偶尔我会得到这个错误。
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不重用一个连接,如果它已经打开。
如果我们试图将部分条件分组到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
在启用MARS和将整个结果集检索到内存之间有一个很好的中间地带,那就是在初始查询中只检索id,然后循环遍历实现每个实体的id。
例如(使用这个答案中的“博客和帖子”样本实体):
using (var context = new BlogContext())
{
// Get the IDs of all the items to loop through. This is
// materialized so that the data reader is closed by the
// time we're looping through the list.
var blogIds = context.Blogs.Select(blog => blog.Id).ToList();
// This query represents all our items in their full glory,
// but, items are only materialized one at a time as we
// loop through them.
var blogs =
blogIds.Select(id => context.Blogs.First(blog => blog.Id == id));
foreach (var blog in blogs)
{
this.DoSomethingWith(blog.Posts);
context.SaveChanges();
}
}
这样做意味着您只需将几千个整数拉入内存,而不是将数千个完整的对象图拉入内存,这将最小化内存使用,同时允许您在不启用MARS的情况下逐项工作。
从示例中可以看到,这样做的另一个好处是,您可以在循环遍历每个项时保存更改,而不必等到循环结束(或其他类似的解决方法),即使启用了MARS也需要这样做(参见这里和这里)。