Почему TransactionScope не работает с Entity Framework?

См. Код ниже. Если я инициализирую более одного контекста объекта, я получаю следующее исключение только для 2-го набора кода. Если я закомментирую второй набор, он работает.

{"Базовый провайдер не удалось открыть."}

Внутренний: {"Связь с базовым диспетчером транзакций не удалась."}

Внутренний: {"Ошибка HRESULT E_FAIL была возвращена из вызова компонента COM."}

Обратите внимание, что это пример приложения, и я знаю, что создавать два контекста подряд не имеет смысла. Однако в производственном коде есть причина для создания нескольких контекстов в одном TransactionScope, и это нельзя изменить.

Изменить

Вот предыдущий вопрос о том, как я пытался настроить MS-DTC. Кажется, что он включен и на сервере, и на клиенте. Я не уверен, правильно ли он настроен. Также обратите внимание, что одна из причин, по которой я пытаюсь это сделать, заключается в том, что существующий код в TransactionScope использует ADO.NET и Linq 2 Sql ... Я бы хотел, чтобы они также использовали ту же транзакцию. (Возможно, это звучит безумно, но мне нужно, чтобы это работало, если возможно).

Как использовать TransactionScope в C #?

Решение

Брандмауэр 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();
        }

person NotDan    schedule 27.04.2009    source источник


Ответы (8)


Ваш MS-DTC (координатор распределенных транзакций) по какой-то причине не работает должным образом. MS-DTC используется для координации результатов транзакций между несколькими разнородными ресурсами, включая несколько соединений sql.

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

В основном, если вы убедитесь, что ваш MS-DTC работает и работает правильно, у вас не должно возникнуть проблем с использованием двух соединений ADO.NET - независимо от того, являются ли они соединениями структуры сущностей или любого другого типа.

person Steve Willcock    schedule 27.04.2009
comment
Теперь это работает. Брандмауэр Windows блокировал подключения к MS-DTC. - person NotDan; 27.04.2009

Вы можете избежать использования распределенной транзакции, управляя своим собственным 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();
}
person Community    schedule 27.04.2009
comment
Я не просто использую Entity Framework, поэтому повторное использование EntityConnection тоже не является простым решением (см. Правку выше) - person NotDan; 27.04.2009
comment
+1 за избежание DTC. Не то чтобы это плохо, просто распределенные транзакции - это не то, что нужно легкомысленно. Это тесная связь приложения и ресурсов, которая изначально создает риск низкой доступности. - person Pontus Gagge; 27.04.2009
comment
Вы также можете вызвать context.Connection.Open (), чтобы управлять им вручную. Вам не нужно создавать EntityConnection вручную - person Sander Rijken; 24.12.2009
comment
Я не понимаю - вы показали пример с одним EntityConnection, поэтому он должен работать, но не работает. Так как же это решение? - person greenoldman; 31.05.2011

Добавьте C: \ Windows \ msdtc.exe в исключения брандмауэра как на брандмауэре, так и на сервере. Я потратил целую вечность на то, чтобы открывать определенные номера портов и диапазоны, но безрезультатно, прежде чем я это сделал.

person burnside    schedule 06.05.2009

Я собираюсь придерживаться этого здесь, потому что вчера я потратил 3 часа с коллегой на отладку этой проблемы. Каждый ответ на этот вопрос говорит о том, что это всегда проблема брандмауэра; однако в нашем случае это не так. Надеюсь, это избавит кого-то от боли.

Ситуация, которая у нас есть, заключается в том, что в настоящее время мы находимся в процессе перехода на Entity Framework. Это означает, что у нас есть части кода, в которых внутри одной транзакции соединения открываются как напрямую с использованием new SqlConnection(connectionString).Open(), так и косвенно с использованием контекста данных EF.

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

Причина ошибки в конечном итоге оказалась в том, что если вы не укажете аргумент Application Name= в строке подключения, Entity Framework добавит его по умолчанию (что-то вроде EntityFrameworkMUF). Это означает, что у вас есть два разных соединения в вашем пуле соединений:

  1. Тот, который вы открываете вручную без аргумента Application Name=
  2. Автоматически сгенерированный с суффиксом Application Name=EntityFrameworkMUF

и невозможно открыть два разных соединения внутри одной транзакции. В производственном коде указано имя приложения; следовательно, это сработало; тестовый код этого не сделал. Указание аргумента Application Name= исправило ошибку для нас.

person satnhak    schedule 29.03.2013
comment
Моя проблема была еще более конкретной: одна строка подключения использовала App=EntityFramework, другая - Application Name = EntityFramework. Лучше всего проверить, если это ваша проблема, - скопировать строку подключения из одного контекста и передать ее в качестве параметра при создании второго. - person Alexander Derck; 23.03.2016

Кстати, вам следует рассмотреть возможность использования SaveChanges (false) в сочетании с AcceptChanges () при использовании подобных явных транзакций.

Таким образом, если что-то не удается в SaveChanges (false), ObjectContext не отбрасывает ваши изменения, поэтому вы можете повторно применить их позже или выполнить регистрацию ошибок и т. Д.

Дополнительную информацию см. В этом сообщении: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx.

Ваше здоровье

Алекс

person Alex James    schedule 02.05.2009

Проблема в том, что два разных DataContext эффективно создают два разных соединения.

В этом случае транзакция ДОЛЖНА быть повышена до распределенной транзакции. Я предполагаю, что ваша проблема связана с настройкой MS DTC (координатора распределенных транзакций Microsoft) на сервере и / или на клиенте. Если сервер не настроен для разрешения удаленных подключений, например, для MSDTC, вы столкнетесь с таким исключением.

вы можете обратиться к этой странице MS, например, для устранения проблем с MSDTC, и Google до краев забит статьями / вопросами на форуме по этому поводу.

Теперь это может быть что-то еще, но действительно похоже, что это проблема MSDTC.

person Denis Troller    schedule 27.04.2009
comment
См. Мою правку выше. Я думаю, что вы правы, и я пытаюсь настроить MS-DTC ... Я не уверен, почему это не работает. - person NotDan; 27.04.2009

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

Вы можете найти этот ответ полезным.

Как включить MSDTC на SQL Server?

person Davy Landman    schedule 27.04.2009

У меня были похожие ошибки при использовании DTC при чтении сообщений из очереди MQ, их обработке и сохранении в базе данных SQL 2005 Express Edition. У меня недостаточно времени, чтобы до конца разобраться, была ли эта проблема вызвана выпуском 2005 г. или исключительно экспресс-версией, но переход на стандарт 2008 г. привел к исчезновению этого конкретного поведения.

person Valdis Iljuconoks    schedule 03.04.2010