Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# `在迭代查询结果时,已存在open DataReader'错误_C#_Entity Framework_Ado.net - Fatal编程技术网

C# `在迭代查询结果时,已存在open DataReader'错误

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);

在我的foreach中,我分配了一个在每次迭代中需要的新变量,但我得到了一个错误:

 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();