在我的foreach中,我在每次迭代中分配了一个我需要的新var,但是我收到一个错误:
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 必须先关闭。
任何帮助,非常感谢
答案 0 :(得分:4)
您创建foreach
循环的方式 - 每次迭代都会读取数据库。一次查询数据库,它应该工作:
foreach (var item in requests.ToList())
当您查询数据库DataReader
再次发送给数据库时,requests
查询的requests.Where(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();
只查询DB一次,循环中的计数在内存中完成。
<强>更新强>
我猜你想要的是以下内容:
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();
}
答案 1 :(得分:1)
如上所述,执行循环时,执行数据库读取的基础DbDataReader
处于打开状态。在循环内部执行另一个查询,因此在连接打开时请求新的结果集。默认情况下,ADO.Net不允许这样做。有几种方法可以解决这个问题:
在连接字符串中设置MultipleActiveResultSets=true
(MARS)。
在循环开始之前实现查询。现在在循环内部,您可以开始新的读取。
重新组织您的代码。仔细观察,在我看来,您不需要重复阅读已售出的金额。您可以在本地跟踪available
(除非此数量由并发用户在外部更改):
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();
在循环之前实现查询可能看起来很有吸引力,但请记住,您将数据拉入内存,而循环期间的读取则以流模式执行查询。如果涉及大量数据,这可能是一个考虑因素。
答案 2 :(得分:-1)
您可以使用以下格式:
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();
}