Son*_*oul 279 linq entity-framework sql-server-2008
我正在使用实体框架,偶尔我会得到这个错误.
EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...
Run Code Online (Sandbox Code Playgroud)
即使我没有做任何手动连接管理.
这个错误间歇性地发生.
触发错误的代码(为了便于阅读而缩短):
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
Run Code Online (Sandbox Code Playgroud)
使用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());
}
}
Run Code Online (Sandbox Code Playgroud)
仍有问题
如果连接已经打开,EF为什么不重用连接?
Lad*_*nka 345
这不是关闭连接.EF正确管理连接.我对这个问题的理解是,在单个连接上执行多个数据检索命令(或者具有多个选择的单个命令),而在第一个DataReader完成读取之前执行下一个DataReader.避免异常的唯一方法是允许多个嵌套的DataReaders =启用MultipleActiveResultSets.总是发生这种情况的另一种情况是,当您遍历查询结果(IQueryable)时,您将在迭代内触发加载实体的延迟加载.
Jim*_*lff 123
或者使用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; }
}
Run Code Online (Sandbox Code Playgroud)
假设您在数据库中进行查找,包含以下内容:
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"));
}
Run Code Online (Sandbox Code Playgroud)
我们可以通过添加.ToList()来做一个简单的解决方案:
var largeBlogs = context.Blogs.Where(b => b.Posts.Count > 5).ToList();
Run Code Online (Sandbox Code Playgroud)
这迫使实体框架将列表加载到内存中,因此当我们在foreach循环中迭代它时,它不再使用数据读取器打开列表,而是在内存中.
我意识到,如果你想延迟加载一些属性,这可能是不可取的.这主要是一个示例,希望能够解释您如何/为什么会遇到此问题,以便您可以做出相应的决策
Rya*_*ndy 67
还有另一种方法可以解决这个问题.是否更好的方式取决于您的情况.
这个问题是由延迟加载引起的,所以避免它的一种方法是不要通过使用Include来延迟加载:
var results = myContext.Customers
.Include(x => x.Orders)
.Include(x => x.Addresses)
.Include(x => x.PaymentMethods);
Run Code Online (Sandbox Code Playgroud)
如果使用适当的Includes,则可以避免启用MARS.但如果你错过了一个,你就会得到错误,因此启用MARS可能是解决它的最简单方法.
Nal*_*ran 46
当您尝试迭代的集合是一种延迟加载(IQueriable)时,会出现此错误.
foreach (var user in _dbContext.Users)
{
}
Run Code Online (Sandbox Code Playgroud)
将IQueriable集合转换为其他可枚举集合将解决此问题.例
_dbContext.Users.ToList()
Run Code Online (Sandbox Code Playgroud)
注意:.ToList()每次创建一个新集合,如果处理大数据,它可能会导致性能问题.
小智 13
我通过向构造函数添加选项轻松地(实用)解决了问题.因此,我只在需要时使用它.
public class Something : DbContext
{
public Something(bool MultipleActiveResultSets = false)
{
this.Database
.Connection
.ConnectionString = Shared.ConnectionString /* your connection string */
+ (MultipleActiveResultSets ? ";MultipleActiveResultSets=true;" : "");
}
...
Run Code Online (Sandbox Code Playgroud)
小智 8
尝试在您的连接字符串中设置"MultipleActiveResultSets = true",这允许在数据库上进行多任务处理."Server = yourserver; AttachDbFilename = database; User Id = sa; Password = blah; MultipleActiveResultSets = true; App = EntityFramework"这对我有用...无论你在app.config中的连接还是以编程方式设置它...希望这个有帮助
| 归档时间: |
|
| 查看次数: |
150858 次 |
| 最近记录: |