C# `在迭代查询结果时,已存在open DataReader'错误
在我的foreach中,我分配了一个在每次迭代中需要的新变量,但我得到了一个错误:C# `在迭代查询结果时,已存在open DataReader'错误,c#,entity-framework,ado.net,C#,Entity Framework,Ado.net,在我的foreach中,我分配了一个在每次迭代中需要的新变量,但我得到了一个错误: public ActionResult question(int? id) { if (id == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } var announcedAmount = db.AnnouncedAmount.Find(id);
public ActionResult question(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var announcedAmount = db.AnnouncedAmount.Find(id);
if (announcedAmount == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
decimal amount = announcedAmount.AmountAnnounced;
var statusOne = db.Dabstats.Single(a => a.StatusName == "Request");
var statusTwo = db.Dabstats.Single(a => a.StatusName == "Sold");
var requests = db.Requests.Where(a => a.annId == id && a.statId == statusOne.statId).OrderBy(a => a.OfferRate);
foreach (var item in requests)
{
decimal sold = requests.Where(a => a.statId == statusTwo.statId).Sum(a => a.soldAmount);
decimal available = amount - sold;
if (available >= item.reqAmount)
{
item.soldAmount = item.reqAmount;
item.StatusId = statusOne.StatusId;
}
db.SaveChanges();
}
return RedirectToAction("Details", new { id = AnnouncedAmount.annId});
}
错误行为:
decimal sold = requests.Where(a => a.statId == statusTwo.statId).Sum(a => a.soldAmount);
以及错误消息:
已存在与此命令关联的打开的DataReader,该命令
必须先关闭
任何帮助,非常感谢您创建
foreach
循环的方法,每次迭代都会读取数据库。立即查询数据库,它应该可以工作:
foreach (var item in requests.ToList())
否则,当您查询数据库中的请求时,您的请求的DataReader
查询仍处于打开状态。其中(a=>a.statId==statusTwo.statId)。Sum(a=>a.soldAmount)
再次发送到数据库
如果在初始查询中添加ToList()
,如下所示:
var requests = db.Requests
.Where(a => a.annId == id && a.statId == statusOne.statId)
.OrderBy(a => a.OfferRate)
.ToList();
数据库只查询一次,循环中的计数在内存中完成
更新:
我想你想要的是如下所示:
var requests = db.Requests
.Where(a => a.annId == id && a.statId == statusOne.statId)
.OrderBy(a => a.OfferRate)
.ToList();
foreach (var item in requests)
{
decimal sold = db.Requests
.Where(a => a.annId == id && a.statId == statusTwo.statId)
.Sum(a => a.soldAmount);
decimal available = amount - sold;
if (available >= item.reqAmount)
{
item.soldAmount = item.reqAmount;
item.StatusId = statusOne.StatusId;
}
db.SaveChanges();
}
您可以使用以下格式:
foreach (var item in Requests)
{
var itemEdit = db.Requests.where(s=>s.Id == item.Id).FirstOrDefault();
decimal sold = Requests.Where(a => a.statId == StatusTwo.statId).Sum(a => a.soldAmount);
decimal available = amount - sold;
if (available >= item.reqAmount)
{
itemEdit.soldAmount = item.reqAmount;
itemEdit.StatusId = StatusOne.StatusId;
}
db.Entry(itemEdit).State = EntityState.Modified;
db.SaveChanges();
}
如上所述,在执行循环时,执行数据库读取的底层DbDataReader
是打开的。在循环内执行另一个查询,因此在连接打开时请求一个新的结果集。默认情况下,ADO.Net不允许这样做。有几种方法可以解决此问题:
在连接字符串中设置MultipleActiveResultSets=true
()
(除非并发用户在外部更改此金额):
在循环之前具体化查询似乎是一个很有吸引力的选择,但请记住,您将数据拉入内存,而在循环期间读取以流模式执行查询。如果涉及大量数据,这可能是一个考虑因素。是否尝试在循环之前的请求中添加ToArray()?请使用适当的标记。此错误与ASP.NET或
foreach
无关。使用ADO.NET和/或实体框架时会出现错误。事实上,如果您搜索此邮件,您会发现许多重复的问题。我不确定此查询是否有任何意义:首先您使用请求
状态查询请求,然后尝试使用已售出
状态筛选结果。不能同时对请求
和出售
进行任何结果。你想干什么?可能有一个更简单、更快的查询将返回您想要的内容。在使用请求
的循环中,它应该是db。请求
@Cubi,它将更改所有相关行的状态。什么格式?这与原始代码有什么不同?为什么它解决了OP的问题?如果有什么不同的话,那么似乎是通过双重加载同一个实体引入了另一个bug。如果原始查询遇到了N+1
问题,那么现在是2N+1
是的,这只会让事情变得更糟。它增加了另一个阅读。此外,如果没有至少一个简短的解释,说明为什么您认为代码解决了问题,那么纯代码的答案是非常无用的。任何人都可以瞎开一枪,希望一些草率的读者投票支持它。标记为“不是答案”,因为它仍然是纯代码的。即使这样也不行,因为OP正在尝试以不同的状态过滤结果。结果将始终为0。这看起来像是缺少映射或表达错误的聚合查询在更改后,它将运行,但有一个错误@PanagiotisKanavos解释说,foreach中的if条件将始终为true,因为销售金额为零并且不会检查it@ChrFin我做得对,我需要检查每一行的内部,然后处理这真的很好,但我尝试了单个事务;我将更改一个并保存,然后我将更改另一个,以便我能够检查可用金额。
var requests = db.Requests.Where(a => a.annId == id && a.statId == statusOne.statId).OrderBy(a => a.OfferRate);
decimal sold = requests.Where(a => a.statId == statusTwo.statId).Sum(a => a.soldAmount);
decimal available = amount - sold;
foreach (var item in requests)
{
if (available >= item.reqAmount)
{
item.soldAmount = item.reqAmount;
item.StatusId = statusOne.StatusId;
available -= item.reqAmount;
}
}
db.SaveChanges();