【问题标题】:db.SaveChanges in ForEach causes 'New transaction is not allowed because there are other threads running in the session'ForEach 中的 db.SaveChanges 导致“不允许新事务,因为会话中正在运行其他线程”
【发布时间】:2021-08-20 22:09:16
【问题描述】:

我有一个大约 21000 行的 excel 文件。我将它导入到我的数据库中的临时表中。

现在我想对我的数据进行一些转换,然后将它们放入我的主表中。

当我在 foreach 内执行 SaveChanges() 时,出现以下错误:

Microsoft.Data.SqlClient.SqlException: 'New transaction is not allowed because there are other threads running in the session

当我在foreach 之后使用它时,没有发生错误,并且表只插入了 4 条记录,而不是我预期的全部 21000 条记录。

     public ActionResult FeedTempdataToMainDB()
    {
        
        var L = new Leave();
        //  var leaves = new List<Leave>();
        foreach (var item in db.TempLeaves)
        {
            L.Pcode = Int32.Parse(item.Cod);
            var z = int.Parse(item.LT) - 1;
            if (z == 0) L.LT = Leave.LeaveType.Saati;
            else L.LT = Leave.LeaveType.Roozane;
            var o = int.Parse(item.DLT) - 1;
            if (o == 0) L.DLT = Leave.DLType.Estehghaghi;
            if (o == 1) L.DLT = Leave.DLType.Estelaji;
            else L.DLT = Leave.DLType.Bihoghoogh;
            L.LeaveDayStart = item.LeaveDayStart.Old6digToMiladi();
            L.LeaveDayEnd = item.LeaveDayEnd.Old6digToMiladi();
            L.LeaveTimeStart = StringToHour(item.LeaveTimeStart);
            L.LeaveTimeEnd = StringToHour(item.LeaveTimeEnd);
            L.LeaveDays = int.Parse(item.LeaveDays);
            L.LeaveMinuts = SaatiLengh(item.LeaveMinuts);
            L.RegDate = StringToHour(item.RegTime);
            L.RegDate = item.RegDate.Old6digToMiladi().Date;
            L.RegistrarCode = Int32.Parse(item.RegistrarCode);
            L.HijriYear = L.LeaveDayStart.GetHijriYear();
            var t = IsOk(item.RegTime);
            if (L.DLT == 0 && t == false || L.LT == 0)
            {
                L.Calculate = false;

                L.IsActive = false;
            }
            else { L.Calculate = true; L.IsActive = true; }
            db.Leaves.Add(L);
            db.SaveChangesAsync();
        }
        //db.SaveChanges();
        return RedirectToAction("index");

【问题讨论】:

  • 你的数据库没有行,因为你做了一个“新的 DatabaseContext”。那么如何保存空的东西呢?
  • 那么为什么它会存储一些记录呢?

标签: c# asp.net asp.net-mvc entity-framework model-view-controller


【解决方案1】:

*这段代码终于奏效了:

public ActionResult FeedTempdataToMainDB()
{
    var leaves = new List<Leave>();
    foreach (var item in db.TempLeaves)
    {
        var L = new Leave();
        L.Pcode = Int32.Parse(item.Cod);
        var z = int.Parse(item.LT) - 1;
        if (z == 0) L.LT = Leave.LeaveType.Saati;
        else L.LT = Leave.LeaveType.Roozane;
        var o = int.Parse(item.DLT);
        if (o == 0) L.DLT = Leave.DLType.Estehghaghi;
        if (o == 1) L.DLT = Leave.DLType.Estelaji;
        else L.DLT = Leave.DLType.Bihoghoogh;
        L.LeaveDayStart = item.LeaveDayStart.Old6digToMiladi();
        L.LeaveDayEnd = item.LeaveDayEnd.Old6digToMiladi();
        L.LeaveTimeStart = StringToHour(item.LeaveTimeStart);
        L.LeaveTimeEnd = StringToHour(item.LeaveTimeEnd);
        L.LeaveDays = int.Parse(item.LeaveDays);
        L.LeaveMinuts = SaatiLengh(item.LeaveMinuts);
        L.RegDate = StringToHour(item.RegTime);
        L.RegDate = item.RegDate.Old6digToMiladi().Date;
        L.RegistrarCode = Int32.Parse(item.RegistrarCode);
        L.HijriYear = L.LeaveDayStart.GetHijriYear();
        var t = IsOk(item.RegTime);
        if (L.DLT == 0 && t == false || L.LT == 0 && t == false)
        {
            L.Calculate = false;

            L.IsActive = false;
        }
        else { L.Calculate = true; L.IsActive = true; }
        leaves.Add(L);
    }

    if (leaves.Count > 0)
    {
        db.Leaves.AddRange(leaves);
        db.SaveChanges();
    }

    return RedirectToAction("index");
}

【讨论】:

    【解决方案2】:

    您的代码中有错误。您在循环之外声明并创建了 L 。每次添加相同的 L 时,只有不同的数据。最后,您将获得在上一次 foreach 循环 cicle 期间创建的相同数据的列表。

    试试这个:

            foreach (var item in db.TempLeaves)
            {
              var z = int.Parse(item.LT) - 1; 
               var L = new Leave{
                Pcode = Int32.Parse(item.Cod),
                LeaveTimeStart = StringToHour(item.LeaveTimeStart),
                LeaveTimeEnd = StringToHour(item.LeaveTimeEnd),
                LeaveDays = int.Parse(item.LeaveDays),
                LT = z == 0? Leave.LeaveType.Saati : Leave.LeaveType.Roozane
                };     
               db.Leaves.Add(L);
            }
    

    或者这个

      var leaves= new List<Leave>();
     foreach (var item in db.TempLeaves)
            {
                var z = int.Parse(item.LT) - 1; 
               var L = new Leave{
                Pcode = Int32.Parse(item.Cod),
                LeaveTimeStart = StringToHour(item.LeaveTimeStart),
                LeaveTimeEnd = StringToHour(item.LeaveTimeEnd),
                LeaveDays = int.Parse(item.LeaveDays),
                LT = z == 0? Leave.LeaveType.Saati : Leave.LeaveType.Roozane
                 };     
               leaves.Add(L);
            }
       if(leaves.Count>0)
    {
       db.Leaves.AddRange(leaves);
      db.SaveChanges();
    }
    

    如果你想使用异步保存,你必须首先进行异步操作。

    【讨论】:

    • 谢谢 Serge 实际上我在这里总结了我的代码以缩短我的评论这里是我的代码:
    • foreach(db.TempLeaves 中的变量项){ L.Pcode = Int32.Parse(item.Cod); var z = int.Parse(item.LT) - 1; if (z == 0) L.LT = Leave.LeaveType.Saati;否则 L.LT = Leave.LeaveType.Roozane; L.LeaveTimeStart = StringToHour(item.LeaveTimeStart); L.LeaveTimeEnd = StringToHour(item.LeaveTimeEnd); L.LeaveDays = int.Parse(item.LeaveDays); db.Leaves.Add(L); }
    • 嗨,Serge 我改变了上面的代码(开始)并在 foreach 循环中使用 db.SaveChangesAsync() 现在我没有错误但表仍然是空的。
    • 我不建议您使用 SaveChangesAsync,尤其是在循环中使用它。使用我的变体 2,它是最可靠的。
    • 非常感谢 Serge 你的代码对我有用,所以我更新了上面的最新代码
    【解决方案3】:

    这里是异步的一个例子:

    private static async Task<Student> GetStudent()
    

    { 学生 student = null;

    using (var context = new SchoolDBEntities())
    {
        Console.WriteLine("Start GetStudent...");
              
        student = await (context.Students.Where(s => s.StudentID == 1).FirstOrDefaultAsync<Student>());
            
        Console.WriteLine("Finished GetStudent...");
    }
    
    return student;
    

    }

    【讨论】:

      【解决方案4】:

      每次 foreach 执行 savechnages 时都会有一个您没有注意控制的线程。由于实体框架正在管理 savechanges 功能。您必须在 foreach 之后执行 savechnages 或使用 async 函数。

      【讨论】:

      • 嗨,Yacine,请告诉我如何使用异步,因为我是 mvc 的初学者。
      猜你喜欢
      • 2016-07-07
      • 1970-01-01
      • 2017-03-27
      • 1970-01-01
      • 2012-09-07
      • 2012-04-23
      • 1970-01-01
      • 2017-06-26
      相关资源
      最近更新 更多