2010-10-28 7 views
8

Viene visualizzato l'errore "Nuova transazione non è consentita perché sono in esecuzione altri thread" in un'applicazione su cui sto lavorando. È sorto durante il refactoring e in particolare durante la creazione di una suite di test.C'è un modo per rilevare i lettori aperti su un SqlConnection?

Mi rendo conto dal guardarsi intorno che significa che probabilmente ho un lettore di dati ancora aperto quando sto creando la transazione, tuttavia è un'app complessa e non mi sembra ovvio il problema. Pertanto mi piacerebbe essere in grado di capire quali lettori sono collegati alla SqlConnection in questione.

Idealmente, voglio essere in grado di aggiungere un orologio in Visual Studio e quindi passare in modalità di debug per vedere quando cambia il numero di lettori connessi.

C'è un modo per farlo? Sto lavorando in C#.

Grazie in anticipo.

Martin

risposta

7

Phew! Bene, so molto di più su Reflection ora!

Per chiunque altro cerchi la risposta a questo, ecco un metodo che restituisce il numero di lettori di dati su un SqlConnection.

public static int CountConnectedReaders(SqlConnection conn) 
{ 
    int readers = 0; 
    Type t = conn.GetType(); 
    MemberInfo[] minf = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance); 
    for (int i = 0; i < minf.Length; i++) 
    { 
    if (minf[i].Name == "get_InnerConnection") 
    {      
     MethodInfo methinf = (MethodInfo)minf[i]; 

     object result = methinf.Invoke(conn, new object[0]); 

     PropertyInfo[] pinfs = result.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance); 
     foreach (PropertyInfo pinf in pinfs) 
     { 
     if (pinf.PropertyType.Name == "DbReferenceCollection") 
     { 
      object dbrc = pinf.GetValue(result, new object[0]); 
      if (dbrc == null) readers = 0; 
      else 
      { 
      MemberInfo[] dbrcInfs = dbrc.GetType().GetMembers(BindingFlags.NonPublic | BindingFlags.Instance); 
      foreach (MemberInfo dbrcInf in dbrcInfs) 
      { 
       if (dbrcInf.Name == "_dataReaderCount") 
       { 
       FieldInfo finf = (FieldInfo)dbrcInf; 
       readers = (Int32) finf.GetValue(dbrc); 
       } 
      } 
      } 
     } 
     } 
    } 
    } 

    return readers; 
} 

È interessante notare che, utilizzando questo nel mio codice problema suggerisce che ci sono lettori di dati aperti sulla connessione quando ho la "nuova transazione non è consentito perché ci sono altri thread in esecuzione" errore in modo nuovo al tavolo da disegno (o almeno un'altra domanda SO) con quello.

+0

Wow, qualcuno ha votato questa risposta (che mi ha richiesto ore per risolverlo) come "non utile". Mi piacerebbe sapere perché. – marsbard

+0

Idioti ovunque. Bella scoperta - Sapevo che non c'era modo di ottenerlo dall'interfaccia documentata, ma ovviamente la connessione doveva avere un riferimento da qualche parte. Bene, almeno un conteggio di lettori aperti. – TomTom

+0

Ben fatto. Votato +1. – TomTom

1

Si potrebbe trovare questo thread di interesse.

Modifica: Sembra che abbiano ottenuto a DbConnectionInternal con Reflector e una versione gratuita è disponibile. Per quanto riguarda la riflessione, non è troppo complicato davvero. C'è una panoramica decente su MSDN.

Edit2: Ho appena realizzato che l'hai già capito. Grande. :) Lascerò la modifica nel caso in cui qualcun altro voglia più informazioni.

+0

Questa è una discussione interessante e pertinente. Sono un po 'fuori dalla mia profondità quando provo ad usare Reflection però :) Inoltre non sono riuscito a trovare il DBConnectionInternal quando si fa clic sugli helper Intellisense in modalità di debug. – marsbard

+0

Grazie per il collegamento a Reflector. Sembra buono. – marsbard

Problemi correlati