Как определить, зачислен ли SqlConnection в tx System.Transactions или нет?

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

1 ответ

Структура, кажется, не позволяет это.

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

Другие вопросы по тегам