Как определить, зачислен ли SqlConnection в tx System.Transactions или нет? - PullRequest
5 голосов
/ 14 октября 2008

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

1 Ответ

8 голосов
/ 14 октября 2008

Фреймворк не позволяет этого.

Возможно, мы могли бы обсудить, почему вам нужно знать эту информацию? 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. Хотя сегодня это работает, может и не завтра.

...