2008-10-14 7 views
5

Kiedy używamy transakcji z System.Transactions (tworzenie TransationScope dla instancji) domyślnie wszystkie połączenia Sql (System.Data.SqlClient.SqlConnection) (ale nie są również prawdziwe dla Oracle.DataAccess.OracleConnection) są wymienione po otwarciu. To się nazywa automatyczna rejestracja. Niezła funkcja. Ale można go wyłączyć za pomocą parametru ciągu połączenia (enlist = false). W takim przypadku otwarte połączenie nie zostanie zarejestrowane. Ale można go później zarejestrować ręcznie. Moje pytanie brzmi: dla pewnej danej instancji SqlConnection, w jaki sposób mogę ustalić, czy to połączenie jest zarejestrowane, czy nie (w System.Transaction). Mogę sprawdzić ciąg połączenia dla parametru. Ale to się nie uda, ponieważ, jak już powiedziałem, połączenie może zostać zarejestrowane ręcznie.Jak ustalić, czy SqlConnection znajduje się w tx System.transactions, czy też nie?

+0

Dobre pytanie. Mój scenariusz jest taki, że mam zestaw, który jest tylko kubłem statycznych metod, które biorą otwarty SqlConnection i CRUD na nim. Byłoby miłe, aby wymusić dołączenie SqlConnection do transakcji przed kontynuowaniem, aby pomóc w ochronie przed logicznym uszkodzeniem aplikacji przez osobę dzwoniącą. Możemy wykryć 'Transaction.Current! = Null' i możemy wykryć' SqlConnection conn! = Null', ale nie możemy sprawdzić, czy conn jest zarejestrowany w transakcji. –

Odpowiedz

7

Wydaje się, że ramy nie pozwalają na to.

Być może moglibyśmy przedyskutować, dlaczego musisz znać te informacje? Platforma TransactionScopeOptions zapewnia elastyczność podczas tworzenia transakcji.

Jednak odmowa "nie" dla odpowiedzi, małe źródło przeglądania później i stworzyłem ten kod, który działa. Zauważ, że ten kod może przestać działać w dowolnym momencie z łatkami do framework'a !!!!

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; 
    } 

Powtórz, to wykorzystuje prywatne i wewnętrzne klasy w ramach .NET. Choć działa dzisiaj, może nie jutro.

+1

+1 za ostrzeżenie "może nie działać jutro". – TcKs

+0

Dzisiaj działa? –

+0

Dzisiaj działa. – TheSoftwareJedi

Powiązane problemy