2008-10-14 11 views
5

Когда мы используем трансацию из System.Transactions (создавая TransationScope для экземпляра) по умолчанию, все Sql-соединения (System.Data.SqlClient.SqlConnection) (но is't также верно для Oracle.DataAccess.OracleConnection) зачисляются сверху открытие. Это называется автоматическим завербованием. Хорошая функция. Но его можно отключить через параметр строки подключения (invist = false). В этом случае соединение, которое открывается, не будет зачислено. Но его можно зачислить вручную позже. Итак, мой вопрос: для какого-то определенного экземпляра SqlConnection, как определить, подключено ли это соединение или нет (в System.Transaction). Я могу посмотреть строку подключения для параметра. Но этого не будет, потому что, как я сказал, соединение может быть завербовано вручную.Как определить, будет ли SqlConnection зачислен в System.Transactions 'tx или нет?

+0

Хороший вопрос. Мой сценарий заключается в том, что у меня есть сборка, которая представляет собой просто ведро статических методов, которые используют Open SqlConnection и CRUD. Было бы неплохо обеспечить, чтобы SqlConnection был зачислен в транзакцию, прежде чем продолжить, чтобы защитить от логического искажения на уровне приложения вызывающим. Мы можем обнаружить `Transaction.Current! = Null`, и мы можем обнаружить` SqlConnection conn! = Null`, но мы не можем проверить, связано ли соединение с транзакцией. – 2010-12-15 21:50:51

ответ

7

Рамки, похоже, не позволяют этого.

Возможно, мы могли бы обсудить, почему вам нужно знать эту информацию? TransactionScopeOptions дает вам некоторую гибкость в отношении того, когда создавать транзакции.

Однако, отказавшись от ответа «нет», немного просмотра источника позже, и я создал этот код, который работает. Обратите внимание, что этот код может перестать функционировать в любое время с исправлениями в фреймворк !!!!

static bool IsEnlisted(SqlConnection sqlConnection) 
    { 
     object innerConnection = typeof(SqlConnection).GetField("_innerConnection", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).GetValue(sqlConnection); 
     var enlistedTransactionField = 
      EnumerateInheritanceChain(innerConnection.GetType()) 
      .Select(t => t.GetField("_enlistedTransaction", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)) 
      .Where(fi => fi != null) 
      .First(); 
     object enlistedTransaction = enlistedTransactionField.GetValue(innerConnection); 
     return enlistedTransaction != null; 
    } 

    static IEnumerable<Type> EnumerateInheritanceChain(Type root) 
    { 
     for (Type current = root; current != null; current = current.BaseType) 
      yield return current; 
    } 

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

+1

+1 для предупреждения «может не работать завтра». – TcKs 2012-01-11 16:26:38