我目前得到这个错误:

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

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


当前回答

我的情况和上面其他人差不多。我有一个IQueryable,我正在做一个foreach。这又调用了一个带有SaveChanges()的方法。此处出现boom异常,因为上面的查询已经打开了一个事务。

// Example:

var myList = _context.Table.Where(x => x.time == null);

foreach(var i in myList)
{
    MyFunction(i); // <<-- Has _context.SaveChanges() which throws exception
}

在我的案例中,将ToList()添加到查询的末尾是解决方案。

// Fix
var myList = _context.Table.Where(x => x.time == null).ToList();

其他回答

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

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

             }

在我的例子中,当我通过EF调用存储过程,然后后来SaveChanges抛出这个异常时出现了问题。问题是在调用过程时,没有处理枚举数。我修复代码如下方式:

public bool IsUserInRole(string username, string roleName, DataContext context)
{          
   var result = context.aspnet_UsersInRoles_IsUserInRoleEF("/", username, roleName);

   //using here solved the issue
   using (var en = result.GetEnumerator()) 
   {
     if (!en.MoveNext())
       throw new Exception("emty result of aspnet_UsersInRoles_IsUserInRoleEF");
     int? resultData = en.Current;

     return resultData == 1;//1 = success, see T-SQL for return codes
   }
}

最近我在我的项目中遇到了同样的问题,所以把我的经验发布出来,它可能会帮助一些和我在同一条船上的人。问题是由于我正在循环EF选择查询的结果(结果没有检索到内存)。

var products = (from e in _context.Products
                              where e.StatusId == 1
                              select new { e.Name, e.Type });

        foreach (var product in products)
        {
           //doing some insert EF Queries
           //some EF select quries
            await _context.SaveChangesAsync(stoppingToken); // This code breaks.
        }

我已经更新了我的产品选择查询,将结果带入LIST而不是IQueryable(这似乎是在为每个循环打开阅读器,因此保存失败)。

 var products = (from e in _context.Products
                              where e.StatusId == 1
                              select new { e.Name, e.Type })**.ToList()**; //see highlighted

供你参考:来自一本书,一些行调整,因为它仍然有效:

调用SaveChanges()方法将启动一个事务,如果在迭代完成之前发生异常,该事务将自动回滚持久化到数据库的所有更改;否则事务将提交。您可能倾向于在每次实体更新或删除之后应用该方法,而不是在迭代完成之后,特别是当您更新或删除大量实体时。

如果在处理完所有数据之前尝试调用SaveChanges(),则会引发“不允许新事务,因为会话中正在运行其他线程”异常。出现异常是因为SQL Server不允许在一个打开了SqlDataReader的连接上启动一个新事务,即使连接字符串启用了多个活动记录集(MARS) (EF的默认连接字符串启用了MARS)。

有时候理解事情为什么会发生会更好;-)

在拔了很多头发之后,我发现foreach loop是罪魁祸首。需要做的是调用EF,但将它返回到目标类型的IList<T>,然后在IList<T>上循环。

例子:

IList<Client> 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;
    // ...
}