Почему 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 исчез из-за того, что это особое поведение.