我目前得到这个错误:

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中插入(如果还没有)。第一次通过应该是充分拉库存。每次在那里运行之后都不会发生任何事情,除非新的库存在夜间进入馈送。

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


当前回答

从EF5迁移到EF6后,我们开始看到这个错误“新事务不允许,因为会话中有其他线程正在运行”。

谷歌将我们带到这里,但我们没有在循环中调用SaveChanges()。在使用ObjectContext执行存储过程时引发错误。从DB读取foreach循环中的ExecuteFunction。

任何对ObjectContext的调用。ExecuteFunction将函数包装在事务中。在已经打开读取器的情况下开始事务会导致错误。

可以通过设置以下选项禁用在事务中包装SP。

_context.Configuration.EnsureTransactionsForFunctionsAndCommands = false;

EnsureTransactionsForFunctionsAndCommands选项允许SP在不创建自己的事务的情况下运行,并且不再引发错误。

DbContextConfiguration。EnsureTransactionsForFunctionsAndCommands财产

其他回答

从EF5迁移到EF6后,我们开始看到这个错误“新事务不允许,因为会话中有其他线程正在运行”。

谷歌将我们带到这里,但我们没有在循环中调用SaveChanges()。在使用ObjectContext执行存储过程时引发错误。从DB读取foreach循环中的ExecuteFunction。

任何对ObjectContext的调用。ExecuteFunction将函数包装在事务中。在已经打开读取器的情况下开始事务会导致错误。

可以通过设置以下选项禁用在事务中包装SP。

_context.Configuration.EnsureTransactionsForFunctionsAndCommands = false;

EnsureTransactionsForFunctionsAndCommands选项允许SP在不创建自己的事务的情况下运行,并且不再引发错误。

DbContextConfiguration。EnsureTransactionsForFunctionsAndCommands财产

我需要读取一个巨大的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属性的简单结构。

所以在项目中,我有这个完全相同的问题,问题不是在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();

如果您由于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();
   }

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

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

             }