我目前得到这个错误:

sqlclient . sqlexception:不允许创建新的事务,因为会话中还有其他线程在运行。

运行这段代码时:

public class ProductManager : IProductManager
{
    #region Declare Models
    private RivWorks.Model.Negotiation.RIV_Entities _dbRiv = RivWorks.Model.Stores.RivEntities(AppSettings.RivWorkEntities_connString);
    private RivWorks.Model.NegotiationAutos.RivFeedsEntities _dbFeed = RivWorks.Model.Stores.FeedEntities(AppSettings.FeedAutosEntities_connString);
    #endregion

    public IProduct GetProductById(Guid productId)
    {
        // Do a quick sync of the feeds...
        SyncFeeds();
        ...
        // get a product...
        ...
        return product;
    }

    private void SyncFeeds()
    {
        bool found = false;
        string feedSource = "AUTO";
        switch (feedSource) // companyFeedDetail.FeedSourceTable.ToUpper())
        {
            case "AUTO":
                var clientList = from a in _dbFeed.Client.Include("Auto") select a;
                foreach (RivWorks.Model.NegotiationAutos.Client client in clientList)
                {
                    var companyFeedDetailList = from a in _dbRiv.AutoNegotiationDetails where a.ClientID == client.ClientID select a;
                    foreach (RivWorks.Model.Negotiation.AutoNegotiationDetails companyFeedDetail in companyFeedDetailList)
                    {
                        if (companyFeedDetail.FeedSourceTable.ToUpper() == "AUTO")
                        {
                            var company = (from a in _dbRiv.Company.Include("Product") where a.CompanyId == companyFeedDetail.CompanyId select a).First();
                            foreach (RivWorks.Model.NegotiationAutos.Auto sourceProduct in client.Auto)
                            {
                                foreach (RivWorks.Model.Negotiation.Product targetProduct in company.Product)
                                {
                                    if (targetProduct.alternateProductID == sourceProduct.AutoID)
                                    {
                                        found = true;
                                        break;
                                    }
                                }
                                if (!found)
                                {
                                    var newProduct = new RivWorks.Model.Negotiation.Product();
                                    newProduct.alternateProductID = sourceProduct.AutoID;
                                    newProduct.isFromFeed = true;
                                    newProduct.isDeleted = false;
                                    newProduct.SKU = sourceProduct.StockNumber;
                                    company.Product.Add(newProduct);
                                }
                            }
                            _dbRiv.SaveChanges();  // ### THIS BREAKS ### //
                        }
                    }
                }
                break;
        }
    }
}

模型#1——这个模型位于我们的开发服务器的数据库中。 模型1 http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/bdb2b000-6e60-4af0-a7a1-2bb6b05d8bc1/Model1.png

模型#2 -这个模型位于我们的Prod服务器的数据库中,每天通过自动馈送进行更新。alt文本http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/4260259f-bce6-43d5-9d2a-017bd9a980d4/Model2.png

注意-模型#1中红圈的项目是我用来“映射”到模型#2的字段。请忽略模型2中的红圈:这是我的另一个问题,现在已经回答了。

注意:我仍然需要放入一个isDeleted检查,这样我就可以从DB1中删除它,如果它已经离开了我们客户的库存。

对于这个特定的代码,我所要做的就是将DB1中的公司与DB2中的客户机连接起来,从DB2中获取他们的产品列表,并在DB1中插入(如果还没有)。第一次通过应该是充分拉库存。每次在那里运行之后都不会发生任何事情,除非新的库存在夜间进入馈送。

所以最大的问题是,我如何解决我得到的事务错误?我是否需要每次通过循环删除并重新创建我的上下文(对我来说没有意义)?


当前回答

总是使用你的选择作为列表

Eg:

var tempGroupOfFiles = Entities.Submited_Files.Where(r => r.FileStatusID == 10 && r.EventID == EventId).ToList();

然后在保存更改时遍历集合

 foreach (var item in tempGroupOfFiles)
             {
                 var itemToUpdate = item;
                 if (itemToUpdate != null)
                 {
                     itemToUpdate.FileStatusID = 8;
                     itemToUpdate.LastModifiedDate = DateTime.Now;
                 }
                 Entities.SaveChanges();

             }

其他回答

所以在项目中,我有这个完全相同的问题,问题不是在foreach或。tolist(),它实际上是在我们使用的AutoFac配置。 这造成了一些奇怪的情况,上面的错误被抛出,但也抛出了一堆其他等效的错误。

这是我们的解决方案: 改变:

container.RegisterType<DataContext>().As<DbContext>().InstancePerLifetimeScope();
container.RegisterType<DbFactory>().As<IDbFactory>().SingleInstance();
container.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();

To:

container.RegisterType<DataContext>().As<DbContext>().As<DbContext>();
container.RegisterType<DbFactory>().As<IDbFactory>().As<IDbFactory>().InstancePerLifetimeScope();
container.RegisterType<UnitOfWork>().As<IUnitOfWork>().As<IUnitOfWork>();//.InstancePerRequest();

I was getting this same issue but in a different situation. I had a list of items in a list box. The user can click an item and select delete but I am using a stored proc to delete the item because there is a lot of logic involved in deleting the item. When I call the stored proc the delete works fine but any future call to SaveChanges will cause the error. My solution was to call the stored proc outside of EF and this worked fine. For some reason when I call the stored proc using the EF way of doing things it leaves something open.

如果您由于foreach而得到这个错误,并且您确实需要在循环中首先保存一个实体,并在循环中进一步使用生成的标识,就像我的情况一样,最简单的解决方案是使用另一个DBContext来插入实体,该实体将返回Id并在外部上下文中使用这个Id

例如

    using (var context = new DatabaseContext())
    {
        ...
        using (var context1 = new DatabaseContext())
        {
            ...
               context1.SaveChanges();
        }                         
        //get id of inserted object from context1 and use is.   
      context.SaveChanges();
   }

我需要读取一个巨大的ResultSet并更新表中的一些记录。 我尝试使用Drew Noakes回答中建议的块。

不幸的是,在50000条记录之后,我得到了OutofMemoryException。 答案实体框架大数据集,内存不足的例外解释,即

EF创建用于更改检测的数据的第二个副本 它可以将更改持久化到数据库)。EF包含第二个集合 在context的生命周期中,这个集合会耗尽你的资源 的内存。

建议为每个批处理重新创建上下文。

所以我已经检索了主键的最小值和最大值-表的主键是自动增量整数。然后通过打开每个块的上下文从数据库中检索记录块。处理完后,块上下文关闭并释放内存。它确保内存使用量不会增长。

下面是我的代码片段:

  public void ProcessContextByChunks ()
  {
        var tableName = "MyTable";
         var startTime = DateTime.Now;
        int i = 0;
         var minMaxIds = GetMinMaxIds();
        for (int fromKeyID= minMaxIds.From; fromKeyID <= minMaxIds.To; fromKeyID = fromKeyID+_chunkSize)
        {
            try
            {
                using (var context = InitContext())
                {   
                    var chunk = GetMyTableQuery(context).Where(r => (r.KeyID >= fromKeyID) && (r.KeyID < fromKeyID+ _chunkSize));
                    try
                    {
                        foreach (var row in chunk)
                        {
                            foundCount = UpdateRowIfNeeded(++i, row);
                        }
                        context.SaveChanges();
                    }
                    catch (Exception exc)
                    {
                        LogChunkException(i, exc);
                    }
                }
            }
            catch (Exception exc)
            {
                LogChunkException(i, exc);
            }
        }
        LogSummaryLine(tableName, i, foundCount, startTime);
    }

    private FromToRange<int> GetminMaxIds()
    {
        var minMaxIds = new FromToRange<int>();
        using (var context = InitContext())
        {
            var allRows = GetMyTableQuery(context);
            minMaxIds.From = allRows.Min(n => (int?)n.KeyID ?? 0);  
            minMaxIds.To = allRows.Max(n => (int?)n.KeyID ?? 0);
        }
        return minMaxIds;
    }

    private IQueryable<MyTable> GetMyTableQuery(MyEFContext context)
    {
        return context.MyTable;
    }

    private  MyEFContext InitContext()
    {
        var context = new MyEFContext();
        context.Database.Connection.ConnectionString = _connectionString;
        //context.Database.Log = SqlLog;
        return context;
    }

FromToRange是一个具有From和To属性的简单结构。

大部分答案与循环有关。但我的问题不同。当我试图在同一范围内使用多个dbcontext.Savechanges()命令时,我多次得到错误。

在我的案例中使用ef core 3.1

dbcontext.Database.BeginTransaction () 而且 dbcontext.Database.CommitTransaction ();

已经解决了问题。以下是我的全部代码:

 public IActionResult ApplyForCourse()
    {

        var master = _userService.GetMasterFromCurrentUser();

            var trainee = new Trainee
            {
                CourseId = courseId,
                JobStatus = model.JobStatus,
                Gender = model.Gender,
                Name = model.Name,
                Surname = model.Surname,
                Telephone = model.Telephone,
                Email = model.Email,
                BirthDate = model.BirthDate,
                Description = model.Description,
                EducationStatus = EducationStatus.AppliedForEducation,
                TraineeType = TraineeType.SiteFirst

            };


            dbcontext.Trainees.Add(trainee);
            dbcontext.SaveChanges();

         
            dbcontext.Database.BeginTransaction();
            var user = userManager.GetUserAsync(User).Result;
            master.TraineeId = trainee.Id;
            master.DateOfBirth = model.BirthDate;
            master.EducationStatus = trainee.EducationStatus;
            user.Gender = model.Gender;
            user.Email = model.Email;
            dbcontext.Database.CommitTransaction();
            dbcontext.SaveChanges();
 
            return RedirectToAction("Index", "Home");

        }


    }