2011-02-03 5 views
0

PCに特定のOracleデータベースを接続する可能性があるかどうかをテストする小さなユーティリティプログラムを作成しました。DBアクセスを行っているバックグラウンドスレッドがハングするUI

UIの応答性を維持し、進捗のステップを見るために、DBコードをバックグラウンドスレッドに配置します。私の驚きには、UIはまだハングアップしています(ただし、それほど多くはありません)。

このアプリは大したことではありませんが、スレッド内のDBコードがUIスレッドをハングアップするという一般的なケースが面白いと思いました。

private void bgwDataAccess_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker bgw = sender as BackgroundWorker; 

     try 
     { 
      bgw.ReportProgress(0, "Starting...\r\n"); 
      bgw.ReportProgress(0, "Active ConnectionString:\r\n"); 
      bgw.ReportProgress(0, Settings.Default.ConnctionString + "\r\n\r\n"); 

      OracleConnection con = new OracleConnection(Settings.Default.ConnctionString); 
      OracleCommand cmd = new OracleCommand("SELECT Count(*) FROM MYTABLE", con); 


      bgw.ReportProgress(0, "Opening db...\r\n"); 
      con.Open(); 
      bgw.ReportProgress(0, "Opened.\r\n\r\n"); 

      bgw.ReportProgress(0, "Executing SQL-query...\r\n"); 
      Object result = cmd.ExecuteScalar(); 
      bgw.ReportProgress(0, String.Format("Result: {0}\r\n\r\n", result.ToString())); 

      con.Close(); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 

    private void bgwDataAccess_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     txtResult.Text += e.UserState;   
    } 
+1

あなたの問題を解決していない小さなメモは、キャッチを削除し、最後にtry-finallyを使用して接続を閉じます。 tryブロックがconオブジェクトを最終的に使用できるようにする前に、接続を宣言する必要があります(開かない)。 –

+0

はい、あなたはそれについて絶対に正しいです! – kaze

+0

「UIスレッドをハングする」を定義/記述できますか?これはどれくらい深刻ですか? –

答えて

1

これ以前にコード内の任意の場所にOracle名前空間にアクセスしていますか?これは単なる推測ですが、必要な.dllをロードするアプリケーションが一時停止している可能性があります

モジュールをプリロードすることができます。私は自分のアプリケーションで以下のようなコードを使用します。最初に、アプリケーションがロード中であることを示すスプラッシュ画面を表示し、必要なdllをすべて読み込むためにスニペットを呼び出します。そうすれば、アプリケーションが読み込まれると、さらに下にポーズはありません。

void PreloadDLLs() 
{ 
    Assembly^ assembly = Assembly::GetEntryAssembly(); 
    array<System::Reflection::AssemblyName^>^ referencedAssemblies = assembly->GetReferencedAssemblies(); 
    for each(System::Reflection::AssemblyName^ referencedAssemblyName in referencedAssemblies) 
    { 
     try 
     { 
      Assembly^ a = assembly->Load(referencedAssemblyName); 
     } 
     catch(System::Exception^ /*e*/) 
     { 

     } 
    } 
} 

C++/CLIの構文について謝罪、うまくいけば、あなたは、C#にそれを変換する方法を見ることができます - 鉱山は少し錆びた:-)だ

[編集]私はこれはかなりのC#だと思います:

using System; 
using System.Reflection; 

private void PreloadDLLs() 
{ 
    Assembly assembly = Assembly.GetEntryAssembly(); 
    System.Reflection.AssemblyName[] referencedAssemblies = assembly.GetReferencedAssemblies(); 
    foreach(System.Reflection.AssemblyName referencedAssemblyName in referencedAssemblies) 
    { 
     try 
     { 
      Assembly a = assembly.Load(referencedAssemblyName); 
     } 
     catch 
     { 

     } 
    } 
} 
+0

あなたの答えをありがとう。私はそれを試しましたが、このケースでは違いはありませんでした。あなたの提案は、おそらく将来的には便利な素晴らしいテクニックですが。 – kaze

+0

価値あるショット:) –

0

クエリを「SELECT top 1 id FROM MYTABLE」に変更すると、影響は同じになります。

これらの操作によって影響が発生しない場合は、プロファイラを使用して、影響を受ける.netコードを特定できます。