我正在使用实体框架,偶尔我会得到这个错误。
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不重用一个连接,如果它已经打开。
我最初决定在我的API类中使用一个静态字段来引用MyDataContext对象的实例(其中MyDataContext是一个EF5 Context对象),但这似乎是造成问题的原因。我在每个API方法中都添加了如下代码,从而解决了这个问题。
using(MyDBContext db = new MyDBContext())
{
//Do some linq queries
}
正如其他人所说,EF数据上下文对象不是线程安全的。因此,在适当的条件下,将它们放置在静态对象中最终会导致“数据读取器”错误。
我最初的假设是只创建对象的一个实例会更有效,并提供更好的内存管理。从我研究这个问题所收集到的资料来看,情况并非如此。事实上,将对API的每个调用视为一个独立的线程安全事件似乎更有效。确保当对象超出作用域时,所有资源都被适当释放。
这是有意义的,特别是如果你把你的API带到下一个自然的进程,即将它公开为WebService或REST API。
信息披露
操作系统:Windows Server 2012
.NET:安装4.5,项目使用4.0
数据来源:MySQL
应用程序框架:MVC3
身份验证:形式
如果我们试图将部分条件分组到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