Почему TransactionScope не работает с Entity Framework? - PullRequest
25 голосов
/ 27 апреля 2009

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

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

Внутренний: {"Не удалось установить связь с соответствующим менеджером транзакций."}

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

Обратите внимание, что это пример приложения, и я знаю, что не имеет смысла создавать 2 контекста подряд. Однако у производственного кода есть причина для создания нескольких контекстов в одном и том же 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();
        }

Ответы [ 8 ]

19 голосов
/ 27 апреля 2009

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

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

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

19 голосов
/ 27 апреля 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();
}
5 голосов
/ 06 мая 2009

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

4 голосов
/ 29 марта 2013

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

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

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

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

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

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

3 голосов
/ 02 мая 2009

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

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

См. Этот пост для получения дополнительной информации: http://blogs.msdn.com/alexj/archive/2009/01/11/savechanges-false.aspx

Приветствия

Alex

1 голос
/ 27 апреля 2009

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

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

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

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

0 голосов
/ 03 апреля 2010

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

0 голосов
/ 27 апреля 2009

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

Этот ответ может оказаться полезным.

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

...