Создание глобального ObjectContext
в веб-приложении очень плохо. Класс ObjectContext
не является потокобезопасным. Она построена вокруг концепции единицы работы , и это означает, что вы используете ее для управления одним вариантом использования: таким образом, для бизнес-транзакции. Он предназначен для обработки одного запроса.
Исключение, которое вы получаете, происходит потому, что для каждого запроса вы создаете новую транзакцию, но пытаетесь использовать ту же самую ObjectContext
. Вам повезло, что ObjectContext
обнаруживает это и выдает исключение, потому что теперь вы узнали, что это не сработает.
Пожалуйста, подумайте об этом, почему это не может работать. ObjectContext
содержит локальный кеш сущностей в вашей базе данных. Это позволяет вам сделать кучу изменений и, наконец, отправить эти изменения в базу данных. При использовании одной статической ObjectContext
, когда несколько пользователей вызывают SaveChanges
для этого объекта, как он должен знать, что именно должно быть зафиксировано, а что нет? Поскольку он не знает, он сохранит все изменения, но в этот момент другой пользователь все еще может вносить изменения. Когда вам повезет, EF или ваша база данных потерпит неудачу, потому что сущности находятся в недопустимом состоянии. Если вам не повезло, объекты в недопустимом состоянии успешно сохранены в базе данных, и через несколько недель вы можете обнаружить, что ваша база данных полна дерьма.
Решением вашей проблемы является создание хотя бы одного ObjectContext
на запрос . Хотя теоретически вы могли бы кэшировать контекст объекта в пользовательском сеансе, это также плохая идея, поскольку ObjectContext
обычно будет жить слишком долго и содержать устаревшие данные (поскольку его внутренний кэш не будет автоматически обновляться).
UPDATE
Также обратите внимание, что наличие одного ObjectContext
на поток так же плохо, как наличие одного экземпляра для всего веб-приложения. ASP.NET использует пул потоков, что означает, что в течение жизненного цикла веб-приложения будет создано ограниченное количество потоков. По сути, это означает, что эти ObjectContext
экземпляры в этом случае все еще будут работать в течение всего жизненного цикла приложения, вызывая те же проблемы с целостностью данных.
Вы можете подумать, что наличие одного DbContext для каждого потока на самом деле потокобезопасно, но обычно это не так, поскольку ASP.NET имеет асинхронную модель, которая позволяет завершать запросы в другом потоке, отличном от того, где он был запущен (и последние версии MVC и Web API даже позволяют произвольному количеству потоков обрабатывать один запрос в последовательном порядке). Это означает, что поток, который запустил запрос и создал ObjectContext
, может стать доступным для обработки другого запроса задолго до того, как этот начальный запрос завершится. Однако объекты, используемые в этом запросе (например, веб-страница, контроллер или любой бизнес-класс), могут по-прежнему ссылаться на этот ObjectContext
. Поскольку новый веб-запрос выполняется в том же потоке, он получит тот же экземпляр ObjectContext
, что и старый запрос. Это снова вызывает состояние гонки в вашем приложении и вызывает те же проблемы безопасности потоков, что и один глобальный экземпляр ObjectContext
.