Как запустить два контекста Entity Framework внутри TransactionScope без MSDTC? - PullRequest
16 голосов
/ 03 марта 2010

Эта проблема не является легко воспроизводимой в простом примере здесь, но было интересно, если у кого-нибудь есть опыт и советы, вот проблема:

  • с использованием Entity Framework
  • имеет много точек в приложении, где (1) данные записываются в некоторую сущность таблицу, например. Клиент, (2) данные записываются в историю таблицу
  • оба этих действий используют Entity Framework, ОДНАКО они используют различные контексты
  • эти действия должны быть оба в одной транзакции : то есть если одно не удается записать, другое не должно писать и т. Д.
  • Я могу обернуть их с помощью TransactionScope,

вот так:

using (TransactionScope txScope = new TransactionScope()) {
    ...
}

но это дает мне:

Координатор распределенных транзакций Microsoft (MSDTC) отключен для сетевые транзакции.

Администратор нашей базы данных сказал мне, что MSDTC по выбору отключен и не может быть установлен .

Поэтому я делаю изменения, пытаясь создать свое собственное EntityConnection с MetadataWorkspace с идеей, что каждый контекст будет использовать одно и то же EntityConnection . Тем не менее, это почти невозможно попытаться заставить его работать, например, в настоящее время я продолжаю получать вышеуказанную ошибку, хотя теоретически оба контекста используют EntityConnection. Трудно понять, где и почему Entity Framework требует MSDTC, например.

Кто-нибудь шел по этому пути раньше, есть опыт или примеры кода, чтобы поделиться?

Ответы [ 3 ]

13 голосов
/ 03 марта 2010

Ну, проблема довольно проста.

Если вы используете sql server 2008, у вас не должно быть этой проблемы, потому что у вас есть продвигаемая транзакция, и, поскольку .NET знает, что вы используете одно и то же постоянное хранилище (базу данных), он не будет продвигать его в DTC и фиксировать как локальный , посмотрите на продвигаемую транзакцию с SQL Server 2008.

Насколько я знаю, Oracle работает в своем драйвере для поддержки продвигаемых транзакций, но я не знаю, состояние, драйвер MS Oracle не поддерживает его. http://www.oracle.com/technology/tech/windows/odpnet/col/odp.net_11.1.0.7.20_twp.pdf

Если вы используете драйвер, который не поддерживает продвигаемые транзакции, для .NET невозможно использовать локальную транзакцию с двумя подключениями. Вам следует изменить архитектуру или убедить администратора базы данных установить MSDTC.

1 голос
/ 05 января 2013

Я думаю, что вам нужно заставить ваши контексты использовать одно соединение с базой данных. После этого вы сможете выполнять эти две операции в двух разных контекстах в одной транзакции. Вы можете достичь этого, передав один объект EntityConnection обоим конструкторам вашего контекста. Конечно, этот подход потребует от вас передать этот объект методам, которые обновляют БД.

Недавно я написал в блоге о создании области контекста базы данных, которая упростит использование нескольких контекстов EF и транзакций.

1 голос
/ 17 февраля 2012

У меня была похожая проблема с SQL 2008, Entity Framework.

У меня были определены две платформы (EF1 и EF2), но с использованием идентичных строк подключения к базе данных SQL 2008.

Я получил ошибку MSDTC выше, при использовании вложенных "usings" для обоих. например код был такой:

using (TransactionScope dbContext = new TransactionScope())
{
     using (EF1 context = new EF1())
     {
         // do some EF1 db call
         using (EF2 context2 = new EF2())
         {
              // do some EF2 db call
          }
      }
      dbContext.Complete();
}

Это было не так просто, потому что это было разделено на несколько методов, но это была основная структура «использования».

Исправлено было открывать только одно использование за раз. Нет ошибки MTDSC, нет необходимости открывать распределенные транзакции на БД.

using (TransactionScope dbContext = new TransactionScope())
{
     using (EF1 context = new EF1())
     {
         // do some EF1 db call

      }
     using (EF2 context2 = new EF2())
     {
              // do some EF2 db call
     }
     dbContext.Complete();
}
...