Почему вставка, использующая код EF, сначала терпит неудачу в TransactionScope? - PullRequest
2 голосов
/ 15 июля 2011

У меня есть ситуация, когда я создаю запись в одной таблице (asset_type) и ссылаюсь на нее через внешний ключ во второй таблице (asset). Обе эти вставки в этой ситуации происходят в одном и том же TransactionScope.

При использовании необработанного соединения DbConnection вставки выполняются успешно:

conn.ConnectionString = "host=localhost;port=5432;database=test_client_alpha;user id=tcauser;password=tcapw";    

using (var trans = new TransactionScope())
{
  conn.Open();
  conn.EnlistTransaction(Transaction.Current);

  var cmd = conn.CreateCommand();
  cmd.CommandText = "INSERT INTO overview.asset_type ( name ) VALUES( 'Unknown' ) RETURNING id";
  var assetTypeId = (int)cmd.ExecuteScalar();

  cmd.CommandText = string.Format("INSERT INTO overview.asset "
                                  + "(asset_type_id, client_id, is_active, is_gps_active, is_virtual, default_lon, default_lat) "
                                  + "VALUES ({0}, 'mid', TRUE, TRUE, FALSE, 0, 0 ) "
                                  + "RETURNING id ", assetTypeId);
  var assetId = (int)cmd.ExecuteScalar();

  trans.Complete();
}

Однако, если я переключусь на использование класса DbContext, вторая вставка (в ресурс) завершится неудачно с нарушением ограничения внешнего ключа, как если бы первая вставка (в asset_type) не произошла:

conn.ConnectionString = "host=localhost;port=5432;database=test_client_alpha;user id=tcauser;password=tcapw";

using (var trans = new TransactionScope())
{
  using (var context = new TestContext(conn, false))
  {
    var assetTypeId = context.Database
      .SqlQuery<int>("INSERT INTO overview.asset_type ( name ) VALUES( 'Unknown' ) RETURNING id")
      .Single();

    var assetId = context.Database
      .SqlQuery<int>(string.Format("INSERT INTO overview.asset "
                                    + "(asset_type_id, client_id, is_active, is_gps_active, is_virtual, default_lon, default_lat) "
                                    + "VALUES ({0}, 'mid', TRUE, TRUE, FALSE, 0, 0 ) "
                                    + "RETURNING id ", assetTypeId))
      .Single();
    trans.Complete();
  }
}

Если я удаляю TransactionScope, пример DbContext выполняется нормально.

Я попытался поиграть с настройками IsolationLevel (ReadCommitted, ReadUncommitted), но безуспешно.

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

Моя база данных - PostgreSQL, и я использую драйверы DevArt dotConnect .NET.

Кто-нибудь знает, почему не работает пример DbContext?

1 Ответ

0 голосов
/ 16 июля 2011

Управление соединениями и транзакциями :

Entity Framework открывает соединения только при необходимости, например, для выполнения запроса или для вызова SaveChanges, а затем закрывает соединение, когдаоперация завершена.

  • Вызов любого из следующих методов открывает соединение:
  • SaveChanges или Обновить для ObjectContext.
  • FirstOrDefault или First для ObjectQuery.
  • Загрузка на EntityCollection.
  • Загрузка на EntityReference.
  • Любой метод встроенного языка (LINQ) или метод построителя запросов ObjectQuery, например, Where, OrderBy или Select.

И затем он открывает еще одно соединение, выброс области транзакцииисключение.Вы должны установить Distributed Transaction Coordinator (не могу сказать, реально это или нет для PostgreSQL).

Если это реально, то после настройки DTC просто откройте ваш conn объект внутри прицела.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...