Почему TransactionScope не работает с Entity Framework?
См. код ниже. Если я инициализирую более одного сущностного контекста, я получаю следующее исключение только в 2-м наборе кода. Если я прокомментирую второй набор, он работает.
{ "Исходный провайдер отказался при открытии." }
Внутренний: { "Не удалось связаться с основным менеджером транзакций".}
Внутренний: { "Ошибка HRESULT E_FAIL была возвращена из вызова COM-компонента".}
Обратите внимание, что это пример приложения, и я знаю, что нет смысла создавать 2 контекста подряд. Однако у производственного кода есть причина для создания нескольких контекстов в одном и том же TransactionScope
, и это не может быть изменено.
Edit
Вот предыдущий вопрос о том, как я пытаюсь настроить MS-DTC. Он кажется включенным как на сервере, так и на клиенте. Я не уверен, правильно ли он настроен. Также обратите внимание, что одна из причин, по которым я пытаюсь это сделать, заключается в том, что существующий код в TransactionScope
использует ADO.NET и Linq 2 Sql... Я бы хотел, чтобы они использовали ту же транзакцию. (Это, вероятно, звучит сумасшедшим, но мне нужно заставить его работать, если это возможно).
Как использовать TransactionScope в С#?
Решение
Брандмауэр Windows блокировал подключения к MS-DTC.
using(TransactionScope ts = new System.Transactions.TransactionScope())
{
using (DatabaseEntityModel o = new DatabaseEntityModel())
{
var v = (from s in o.Advertiser select s).First();
v.AcceptableLength = 1;
o.SaveChanges();
}
//-> By commenting out this section, it works
using (DatabaseEntityModel o = new DatabaseEntityModel())
{
//Exception on this next line
var v = (from s1 in o.Advertiser select s1).First(); v.AcceptableLength = 1;
o.SaveChanges();
}
//->
ts.Complete();
}
Ответы
Ответ 1
Ваш MS-DTC (координатор распределенных транзакций) по какой-то причине не работает должным образом. MS-DTC используется для координации результатов транзакций по нескольким неоднородным ресурсам, включая несколько соединений sql.
Посмотрите эту ссылку для получения дополнительной информации о том, что происходит.
В принципе, если вы убедитесь, что ваш MS-DTC работает и работает правильно, у вас не должно возникнуть проблем с использованием двух подключений ADO.NET - независимо от того, являются ли они сущностными соединениями или любым другим типом.
Ответ 2
Вы можете избежать использования распределенной транзакции, управляя своим собственным EntityConnection и передавая этот EntityConnection в свой ObjectContext. В противном случае проверьте их.
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=580828&SiteID=1&mode=1
http://forums.microsoft.com/msdn/showpost.aspx?postid=113669&siteid=1&sb=0&d=1&at=7&ft=11&tf=0&pageid=1
EntityConnection conn = new EntityConnection(ConnectionString);
using (TransactionScope ts = new TransactionScope())
{
using (DatabaseEntityModel o = new DatabaseEntityModel(conn))
{
var v = (from s in o.Advertiser select s).First();
v.AcceptableLength = 1;
}
//-> By commenting out this section, it works
using (DatabaseEntityModel o = new DatabaseEntityModel(conn))
{
//Exception on this next line
var v = (from s1 in o.Advertiser select s1).First();
v.AcceptableLength = 1;
}
//->
ts.Complete();
}
Ответ 3
Добавьте C:\Windows\msdtc.exe в исключения брандмауэра как на брандмауэре, так и на сервере. Я потратил много времени на то, чтобы открыть определенные номера портов и диапазоны, но не помогло, прежде чем я это сделал.
Ответ 4
Я собираюсь придерживаться этого здесь, потому что я провел 3 часа с коллегой вчера, отлаживая эту проблему. Каждый ответ, связанный с этим, говорит, что это всегда проблема брандмауэра; однако в нашем случае это было не так. Надеюсь, это избавит кого-то от боли.
Ситуация, которая у нас есть, заключается в том, что мы в настоящее время находимся в процессе перехода на Entity Framework. Это означает, что у нас есть части кода, где внутри одного соединения транзакции открываются как напрямую, используя new SqlConnection(connectionString).Open()
, так и косвенно, используя контекст данных EF.
Это работает в нашем приложении некоторое время, но когда мы начали ретроспективно идти и ставить тесты вокруг кода, который работал на производстве, код, выполняемый из тестового бегуна, все время бросал эту ошибку в первый раз, когда объект EF попытался подключиться к базе данных после, было произведено прямое соединение в той же транзакции.
Причиной ошибки в конечном итоге оказалось то, что если вы не передаете аргумент Application Name=
в строку подключения, то Entity Framework добавляет по умолчанию (что-то вроде EntityFrameworkMUF
). Это означает, что у вас есть два разных соединения в пуле соединений:
- Тот, который вы открываете вручную без аргумента
Application Name=
- Автоматически сгенерированный суффикс
Application Name=EntityFrameworkMUF
и невозможно открыть два разных соединения внутри одной транзакции. В производственном коде указано имя приложения; следовательно, это сработало; в тестовом коде нет. Указание аргумента Application Name=
исправило ошибку для нас.
Ответ 5
Кстати, вы должны использовать SaveChanges (false) в сочетании с AcceptChanges(), когда используете Явные транзакции, подобные этому.
Таким образом, если что-то не удается в SaveChanges (false), ObjectContext не отменил ваши изменения, поэтому вы можете повторно применить позже или сделать некоторые записи ошибок и т.д.
Смотрите это сообщение для получения дополнительной информации: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx
Приветствия
Алекс
Ответ 6
Проблема состоит в том, что 2 разных DataContext эффективно создают два разных соединения.
В этом случае транзакция должна быть повышена до распределенной транзакции. Я предполагаю, что ваша проблема связана с согласованием MS DTC (Microsoft Distributed Transaction Coordinator) на сервере и/или с клиентом.
Если сервер не настроен для разрешения удаленных подключений для MSDTC, например, вы столкнетесь с таким исключением.
вы можете обратиться к этой странице MS, например, для устранения неполадок MSDTC, а google заполнен до краев вопросами статей/форума о он.
Теперь это может быть что-то другое, но похоже, что это проблема MSDTC.
Ответ 7
Я написал ответ в другом вопросе о том, как диагностировать транзакции MSDTC.
Вы можете найти ответ полезным.
Как включить MSDTC на SQL Server?
Ответ 8
У меня были подобные ошибки при использовании DTC при чтении сообщений из очереди MQ, их обработке и хранении в базе данных SQL 2005 Express Edition. У меня недостаточно времени для расследования до конца, вызвала ли это проблема 2005 года или вышла экспресс-версия, но переход на 2008 год Standard исчез из-за того, что это особое поведение.