SqlException от Entity Framework - Новая транзакция не разрешена, поскольку в сеансе запущены другие потоки - PullRequest
549 голосов
/ 22 января 2010

Я сейчас получаю эту ошибку:

System.Data.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 - эта модель находится в базе данных на нашем Dev-сервере. Модель # 1 http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/bdb2b000-6e60-4af0-a7a1-2bb6b05d8bc1/Model1.png

Модель # 2 - Эта модель находится в базе данных на нашем Prod Server и обновляется каждый день автоматическими лентами. альтернативный текст 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, если его там еще нет. Первый раз должен быть полный запас инвентаря. Каждый раз, когда он запускается там, после того, как ничего не произойдет, если за ночь не появятся новые материалы на корме.

Итак, большой вопрос - как мне исправить полученную ошибку транзакции? Нужно ли мне каждый раз отбрасывать и пересоздавать свой контекст через циклы (не имеет смысла для меня)?

Ответы [ 19 ]

2 голосов
/ 21 июля 2015

Таким образом, в проекте, где у меня возникла та же самая проблема, проблема была не в foreach или .toList(), а на самом деле в конфигурации AutoFac, которую мы использовали. Это создало некоторые странные ситуации, в которых была выдана вышеупомянутая ошибка, но также было выдано множество других эквивалентных ошибок.

Это было наше исправление: Изменено это:

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

Кому:

container.RegisterType<DataContext>().As<DbContext>().As<DbContext>();
container.RegisterType<DbFactory>().As<IDbFactory>().As<IDbFactory>().InstancePerLifetimeScope();
container.RegisterType<UnitOfWork>().As<IUnitOfWork>().As<IUnitOfWork>();//.InstancePerRequest();
1 голос
/ 10 марта 2011

Я тоже столкнулся с той же проблемой.

Вот причина и решение.

http://blogs.msdn.com/b/cbiyikoglu/archive/2006/11/21/mars-transactions-and-sql-error-3997-3988-or-3983.aspx

Убедитесь, что перед выполнением команд обработки данных, таких как вставки, обновления, вы закрыли все предыдущие активные программы чтения SQL.

Самая распространенная ошибка - это функции, которые читают данные из БД и возвращают значения. Например, для таких функций, как isRecordExist.

В этом случае мы немедленно возвращаемся из функции, если нашли запись, и забываем закрыть читатель.

1 голос
/ 15 января 2018

Если вы получаете эту ошибку из-за 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();
   }
1 голос
/ 26 сентября 2015

В моем случае проблема возникла, когда я вызвал хранимую процедуру через 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
   }
}
0 голосов
/ 25 марта 2014

Код ниже работает для меня:

private pricecheckEntities _context = new pricecheckEntities();

...

private void resetpcheckedtoFalse()
{
    try
    {
        foreach (var product in _context.products)
        {
            product.pchecked = false;
            _context.products.Attach(product);
            _context.Entry(product).State = EntityState.Modified;
        }
        _context.SaveChanges();
    }
    catch (Exception extofException)
    {
        MessageBox.Show(extofException.ToString());

    }
    productsDataGrid.Items.Refresh();
}
0 голосов
/ 24 ноября 2017

Я знаю, что это старый вопрос, но я столкнулся с этой ошибкой сегодня.

и я обнаружил, что эта ошибка может возникать, когда триггер таблицы базы данных получает ошибку.

для вашей информации, вы можете проверить триггеры таблиц, когда вы получите эту ошибку.

0 голосов
/ 08 ноября 2016

Я немного опоздал, но у меня тоже была эта ошибка. Я решил проблему, проверив, что, где значения, которые, где обновление.

Я обнаружил, что мой запрос был неправильным и что там более 250+ изменений, ожидающих рассмотрения. Поэтому я исправил свой запрос, и теперь он работает правильно.

Итак, в моей ситуации: Проверьте запрос на наличие ошибок, отладив результат, который возвращает запрос. После этого исправьте запрос.

Надеюсь, это поможет решить будущие проблемы.

0 голосов
/ 30 августа 2018

Создание списков с запросом в .ToList (), и оно должно работать нормально.

0 голосов
/ 03 июня 2016

Я сильно опоздал на вечеринку, но сегодня я столкнулся с той же ошибкой, и то, как я решил, было просто. Мой сценарий был похож на данный код, который я выполнял в БД внутри вложенных циклов for-each.

Проблема в том, что транзакция с одной БД занимает немного больше времени, чем цикл for-each, поэтому, как только более ранняя транзакция не завершена, новая тяга выдает исключение, поэтому решение заключается в создании нового объекта в for -Каждый цикл, в котором вы делаете транзакцию БД.

Для вышеупомянутых сценариев решение будет таким:

foreach (RivWorks.Model.Negotiation.AutoNegotiationDetails companyFeedDetail in companyFeedDetailList)
                {
private RivWorks.Model.Negotiation.RIV_Entities _dbRiv = RivWorks.Model.Stores.RivEntities(AppSettings.RivWorkEntities_connString);
                    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 ### //
                    }
                }
...