Параллельный доступ к базе данных с Entity Framework == EntityException - PullRequest
8 голосов
/ 28 февраля 2011

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

Мой linq доступен службам WCF в режиме создания экземпляров PerCall для тяжелого приложения.Это приложение имеет несколько потоков, которые выполняют вызовы службы, и несколько приложений работают в одно и то же время.

У меня часто происходит некоторое исключение EntityException:

System.Data.EntityException былоcatch Message = Произошла ошибка при запуске транзакции в соединении провайдера.Смотрите внутреннее исключение для деталей.Source = System.Data.Entity StackTrace: в System.Data.EntityClient.EntityConnection.BeginDbTransaction (IsolationLevel изоляцияLevel) в System.Data.EntityClient.EntityConnection.BeginTransaction () в System.Data.Objects.ObjectContext.Infoteam.GfK.TOMServer.DataServer.DataServer.SaveChanges () в D: \ Workspace \ XYZWASDF \ DataServer \ DataServer.cs: строка 123 InnerException: System.Data.SqlClient.SqlException Сообщение = транзакция нового запроса для подтвержденияПотоки темы не выходят за рамки сессии.Источник = .Net SqlClient Поставщик данных ErrorCode = -2146232060 Класс = 16 LineNumber = 1 Number = 3988 Процедура = "" Сервер = ift-srv114 State = 1 StackTrace: at System.Data.SqlClient.SqlConnection.OnError (исключение SqlException, логическое breakConnection) в System.Data.SqlClient.SqlInternalConnection.OnError (исключение SqlException, логическое breakConnection) в System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning () в System.Data.SqlClient.TdsParser.RuniorSlayerShlvSlayer для SqSlayerBulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) при System.Data.SqlClient.TdsParser.TdsExecuteTransactionManagerRequest (байт [] буфера, запрос TransactionManagerRequestType, Строка transactionName, TransactionManagerIsolationLevel isoLevel, Int32 тайм-аута, SqlInternalTransaction транзакции, TdsParserStateObject stateObj, булева isDelegateControlRequest) при System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransactionYukon (TransactionRequest transactionRequest, String transactionName, IsolationLevel изо, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest) в System.Data.SqlClient.SqlInternalConnectionTds.ExecuteTransaction (TransactionRequest transactionRequest, имя String, IsolationLevel изо, SqlInternalTransaction internalTransaction, Boolean isDelegateControlRequest) в System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, StringactionName) в System.Data.SqlClient.SqlInternalConnection.BeginTransaction (IsolationLevel iso) в System.Data.SqlClient.SqlConnection.BeginDbTransaction (IsolationLevel изоляционный уровеньLevelLevelLection (уровень).System.Data.EntityClient.EntityConnection.BeginDbTransaction (IsolationLevel изоляцияLevel) InnerException:

(извините, он не очень читаемый).(Сообщение о внутреннем исключении означает «Новая транзакция не разрешена, потому что в сеансе запущены другие потоки».

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

любая помощь будет по достоинству оценена:)

Спасибо!

РЕДАКТИРОВАТЬ: Вотпример того, где я получил это исключение ИНОГДА

    //My DataServer method, which is a singleton

    [MethodImpl(MethodImplOptions.Synchronized)]
            public void SaveChanges()
            {
                lock (_lockObject)
                {
                    try
                    {
                        _context.SaveChanges(SaveOptions.AcceptAllChangesAfterSave);
                        _changeListener.ManageIDAfterInsert();                       
                    }
                    catch (Exception ex)
                    {
                        Logger.Instance.Error("[DataServer:SaveChanges] Got an error when trying to save an object", ex);
                        //HERE I've this error
                    }
                }
            }

//One example where I can have exception sometimes, this is called through a WCF service, so I have a method which attach the object and then save it
private OrderStatus AddOrderStatus(OrderStatus orderStatus)
        {
            DataServer.DataServer.Instance.InsertOrUpdateDetachedObject(orderStatus);

            return orderStatus;
        }

1 Ответ

7 голосов
/ 28 февраля 2011

Не видя ваш код, короткий ответ заключается в том, что EntityFramework не является потокобезопасным.Вы получаете эту ошибку в на первый взгляд случайной схеме, когда два + потока перекрываются при попытке доступа к вашему ObjectContext.Я предполагаю, что вы вставили свой контекст в переменную static.Либо сделайте контекст локальной переменной, либо запишите блокировку доступа к ObjectContext.

. Если вы хотите получить более конкретный ответ, вам поможет публикация кода.

Редактировать

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

  • В вашем примере кода _ lockObject является статической переменной?
  • Почему вы показываете блокировку в SaveChanges, а затем объясняете, что из InsertOrUpdateDetachedObject выдается ошибка?Можем ли мы увидеть код для InsertOrUpdateDetachedObject?
  • Использует ли SaveChanges тот же _lockObject, что и для всех других методов, напрямую обращающихся к контексту?
  • Является ли ваш вызов _context.SaveChanges единственным способомВы сохраняете в БД или у вас есть другие области, которые открывают контексты транзакций самостоятельно?
  • Вы используете singleton, поэтому ваш контекст распределяется между несколькими вызовами.Может быть предпочтительнее создавать новый новый контекст для каждого вызова WFC.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...