2012-02-16 14 views
14

私はいくつかのコードを見て、同僚と議論していました。using connection.open with statement

特にこのようなコードセクション。

[Test] 
    public void TestNormalWay() 
    { 
     using(var cn = GetConnection()) 
     { 
      cn.Open(); 
      // do stuff 
     } 
    } 

質問が来た:

"なぜGetConnectionメソッドにcn.Openを移動しません。"

私は、 "オープン"が例外をスローするとディスパッチは呼び出されないと言った。彼の答えは

た「だから何な接続がそのように開かれていませんでした。なぜそれが が閉じて(または配置された)を取得する必要があるでしょうか?」

私にとっては、私がディスパージ/クローズする必要があるかどうかを知りたいのではなく、共有機能に移動するのではなく、コード内でcn.Openを繰り返すことです。

しかしそれは面白いですが...私はcn.Openを呼び出すと、それがスローするシナリオと例外処分は希望がある場合は私にSQL Server Connection Pooling (ADO.NET)

でいくつかの読書は、それが明確ではありませんでした呼び出される必要があります。以下の私の例ではそう

あなたは常には、すぐにそれはだとして、接続を開きたい、本当に「TestNormalWay」と「WhyNotDoItThisWay」

protected static DbConnection GetConnection() 
    { 
     DbConnection cn = new SqlConnection("SomeConnecitonstring... "); 
     return cn; 
    } 

    protected static DbConnection GetConnectionDangerousVersion() 
    { 
     DbConnection cn = new SqlConnection("SomeConnecitonstring... "); 
     cn.Open(); // this will throw.. .dispose not called 
     return cn; 
    } 

    [Test] 
    public void TestNormalWay() 
    { 
     using(var cn = GetConnection()) 
     { 
      cn.Open(); 
      // do stuff 
     } 
    } 

    [Test] 
    public void WhyNotDoItThisWay() 
    { 
     using(var cn = GetConnectionDangerousVersion()) 
     { 
      // do stuff 
     } 
    } 
+0

あなたは何を言っているかに基づいています。そして、DisposeがWhyNotDoItTHisWayメソッドで呼び出される唯一の方法を見ています。あなたがOpenを呼び出したからといって、自動的に接続を破棄しないからです。 .vnをusing(){}にラップすると、cnは自動的に破棄され、そのインスタンスも同様に新しいものとみなされます。 – MethodMan

+0

** using **ステートメントを使用している場合は、あなた自身のオブジェクト。接続を開こうとしたときに例外が発生した場合、あなたの同僚が疑うように、オブジェクトには実際に処分する情報が含まれていません。さらに、Servyが提案しているように、本当に安全であることが必要な場合は、try()catch()finally()ブロックを単純に使用できます。 –

答えて

7

の間に違いはあなたのコードを書いている方法があります違いがないように作成されています。

ただし、接続を複数回開いたり閉じたりすることができます。そのためには、大きな違いがあります。

私は接続オブジェクトをとり、時間がたつにつれて開いたり閉じたりする長い実行ルーチンがあるところで、いくつかのコードを記述したいかもしれません。ルーチンは、接続オブジェクトの作成方法を気にしないかもしれません。したがって、接続を作成する行為とそれを開閉する行為を分離することは利点です。

私はそれが問題ではないと私は同意していたリソース管理の質問に関して。 SQL接続オブジェクト自体を作成してもリソースはロックされませんが、プールされた接続を取得するのはそれを開く動作です。 openが例外を返す場合は、接続が開かれていないと仮定するのが妥当だと思います。

+0

両方の方法を提供することもできます。 「GetOpenConnection」と「GetUnopenedConnection」を使用して、いずれかを行うことができますが、最も一般的なケースでは入力する必要はありません。 – Servy

+1

あなたはできますが、IMHOは良いAPIデザインではありません。 APIは最小限に抑えて、私にAPIを設計する醜い方法のような入力を減らすために、このような複合メソッドを提供する必要があります。しかし、そのような接続オブジェクトが必要な場合は、ラッパーを記述することができます。 –

+0

合意。それが単なる短いコード行以上であれば議論する価値はあるかもしれませんが、APIを乱雑にするのは簡単です。 OPが最初に投稿を開始したことを考えると、これは誰かにとって価値があるようですので、とにかく言及しました。 – Servy

1

2回目の "危険な"バージョンで.Open()呼び出しをtry/catchすることで、開いている間に例外がスローされても接続が破棄されるようにすることができます。

+0

それを返す前に接続を破棄しないでください...その時点で何がポイントですか? –

+0

@jsoboあなたは正しいです。 try/catchする必要があります、最後に試してください。編集されました。 – Servy

6

あなたのメソッドでOpen()を呼び出さずに、SqlConnectionのインスタンスを返すことになります。それが必要な場合は、それを行う必要があります。あなたのユーティリティ機能では必要ありません。

理由の1つは、SqlConnectionが必要なオブジェクトがいくつかありますが、必ずしもそれらを開く必要はありません。たとえば、SqlDataAdapterSqlConnectionで、それ自体の開閉を処理します。確かに、あなたはそれを渡す前に接続を開くことができますが、あなたはそれを閉じることで明示的にする必要があります。

少し前に戻って、SqlConnectionと正確に何を処理するかは、呼び出し元コードの責任で行う必要があります。

+0

これは最も安全なオプションであり、それは、少なくともそれは常に(...電源コードなどを引いて誰かがなければ)と呼ばれるようになりますとき、あなたはこれを処分呼び出す必要がある場合にとして曖昧であるため、 –

+0

私は、全体のMSDNの記事を再読し、これを見つけました...」接続がプールに返されるように、接続の終了時に常に接続を閉じることを強くお勧めします。これは、ConnectionオブジェクトのCloseメソッドまたはDisposeメソッドを使用するか、 C#でのusingステートメント内のすべての接続を開く "...もう一度あいまいなステートメント。あなたが実際に接続でopenを指定したことを指定していません!あなたはそれを使っただけです。 –

0

SqlConnectionの内部をピークにした後、私は本当に問題ではないと確信しています。簡単なテストではこれを確認しているようです:

static void Main(string[] args) 
{ 
    Func<SqlConnection> getConnection = 
      () => 
       { 
        var connection = 
        new SqlConnection(
         "Initial Catalog=myDatabase;Server=(local);Username=bogus;password=blah;Connect Timeout=10;"); 

        connection.Open(); 
        return connection; 
       }; 

    while(true) 
    { 
     try 
     { 
     using(var connection = getConnection()) 
     { 
      var cmd = new SqlCommand("SELECT 1", connection) {CommandType = CommandType.Text}; 
      cmd.ExecuteNonQuery(); 
     } 
     } 
     catch (Exception) 
     { 
     // ignore exception 
     } 
    } 
} 

このコードは、プロファイラを付けて数分間実行したままにしておきます。それは非常に速く走っているだけでなく、メモリを漏らしていません。これにより、GetConnectionメソッドで接続を開いても大丈夫です。

もちろん、ここに掲載されているその他の議論はすべて有効です。あなたがすぐにそれを使用する場合は、接続を開く必要があります。

+0

これは必ずしも何かを証明するものではありません。接続が開いていても失敗するのはどうですか...接続プールが作成され、リソースが取得されて処分されないのはどうですか? IE ...オープンは実際には開いていませんが、コネクションをリセットしようとしていますか? –

+0

@jsobo [OK]を、どうしたらそれをテストしますか?私は、作業用と非作業用の接続文字列とさまざまな種類のエラーのさまざまな組み合わせを試しました。私が知る限り、 'SqlConnection.Open'が例外をスローするときはいつでも、それは基礎となるリソースをすべてクリーンアップします。 –

+0

私には分かりません。あなたが試すことができないシナリオがたくさんあります。問題は本当にあなたが処分されなければならない何かを得るときによって決定されます... NEW時またはOPEN時に決定されます。あなたが新しいと...プールから何かを取得すると、既存の接続に接続をリセットして開きます...それからあなたはより良いdisposeを呼び出します...プールから取得し、カバーの下でリセットする –