5

2 つの質問があります。

1) 接続では常に using ステートメントを使用する必要がありますか? それで、接続でそれを使用してから、接続内のリーダーで別のものを使用しますか? したがって、2 つの using ステートメントを使用します。

2) 接続で using ステートメントを使用し、接続で返されるリーダーも使用するとします。したがって、2 つの using ステートメントがあります。Try{}Finally{} ブロックを 2 つ作成しますか、それとも 1 つだけ作成しますか?

ありがとう!

4

6 に答える 6

7

ここでは注意してください。IDisposableを実装するローカルオブジェクトには、常にusingステートメントが必要です。これには、接続とリーダーだけでなく、コマンドも含まれます。しかし、それは時々、そのusingステートメントがどこに行くのか正確にトリッキーになる可能性があります。注意しないと問題が発生する可能性があります。たとえば、次のコードでは、usingステートメントを使用する前にリーダーを閉じます。

DataReader MyQuery()
{
    string sql="some query";
    using (var cn = new SqlConnection("connection string"))
    using (var cmd = new SqlCommand(sql, cn))
    {
        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            return rdr;
        }
    }
}

代わりに、4つのオプションがあります。1つは、関数を呼び出すまでusingブロックの作成を待つことです。

DataReader MyQuery()
{
    string sql="some query";
    using (var cn = new SqlConnection("connection string"))
    using (var cmd = new SqlCommand(sql, cn))
    {
        cn.Open();
        return cmd.ExecuteReader();
    }
}

using (var rdr = MyQuery())
{
    while (rdr.Read())
    {
        //...
    }
}

もちろん、そこでの接続には注意が必要です。つまり、関数を使用するすべての場所でusingブロックを作成することを忘れないでください。

オプション2は、メソッド自体でクエリ結果を処理するだけですが、これにより、プログラムの他の部分からのデータレイヤーの分離が解除されます。3番目のオプションは、MyQuery()関数がwhile(rdr.Read())ループ内で呼び出すことができるAction型の引数を受け入れることですが、それは厄介です。

私は一般的にオプション4を好みます:データリーダーを次のようにIEnumerableに変えます:

IEnumerable<IDataRecord> MyQuery()
{
    string sql="some query";
    using (var cn = new SqlConnection("connection string"))
    using (var cmd = new SqlCommand(sql, cn))
    {
        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
              yield return rdr;
        }
    }
}

これで、すべてが正しく閉じられ、それを処理するコードがすべて1か所にまとめられます。また、すばらしいボーナスが得られます。クエリ結果は、どのlinq演算子でもうまく機能します。

最後に、次に私が遊んでいる新しいものは、IEnumerableとデリゲート引数の受け渡しを組み合わせた完全に新しいプロジェクトを構築することになります。

//part of the data layer
private static IEnumerable<IDataRecord> Retrieve(string sql, Action<SqlParameterCollection> addParameters)
{
    //DL.ConnectionString is a private static property in the data layer
    // depending on the project needs, it can be implementing to read from a config file or elsewhere
    using (var cn = new SqlConnection(DL.ConnectionString))
    using (var cmd = new SqlCommand(sql, cn))
    {
        addParameters(cmd.Parameters);

        cn.Open();
        using (var rdr = cmd.ExecuteReader())
        {
            while (rdr.Read())
              yield return rdr;
        }
    }
}

そして、次のようにデータレイヤー内で使用します。

public IEnumerable<IDataRecord> GetFooChildrenByParentID(int ParentID)
{
    //I could easily use a stored procedure name instead, and provide overloads for commandtypes.
    return Retrieve(
        "SELECT c.* 
         FROM [ParentTable] p 
         INNER JOIN [ChildTable] c ON c.ParentID = f.ID 
         WHERE f.ID= @ParentID", p => 
       {
          p.Add("@ParentID", SqlDbType.Int).Value = ParentID;
       }
     );
}
于 2010-04-03T16:23:47.407 に答える
5

1)接続で常にusingステートメントを使用する必要がありますか?それで、私はそれを接続で使用し、次に接続内のリーダーで別のものを使用しますか?したがって、2つのusingステートメントを使用します。

はい、実装しているためIDisposableです。usingまた、コマンドのステートメントも忘れないでください:

using (DbConnection connection = GetConnection())
using (DbCommand command = connection.CreateCommand())
{
    command.CommandText = "SELECT FOO, BAR FROM BAZ";
    connection.Open();
    using (DbDataReader reader = command.ExecuteReader())
    {
        while (reader.Read())
        {
            ....
        }
    }
}

2)接続でusingステートメントを使用し、接続でリーダーが返されるとします。したがって、2つのusingステートメントがあります。2つのTry{}Finally {}ブロックを作成しますか、それとも1つだけ作成しますか?

usingステートメントは独自のtry/finallyブロックを作成します

于 2010-04-03T16:24:34.410 に答える
4
  1. usingオブジェクトが を実装するときは、常にステートメントを使用する必要がありますIDisposable。これには接続が含まれます。

  2. ネストされた 2 つのtry{}finally{}ブロックが作成されます。

于 2010-04-03T16:13:47.290 に答える
2

1)の特筆事項。接続が非同期 ADO.NET メソッド(BeginExecuteReader など) で使用されている場合は、特にその手法を避ける必要があります。これは、非同期操作がまだ進行中にスコープから外れて接続を破棄しようとする可能性が高いためです。これは、ローカル変数ではなくクラス変数を使用している場合と似ています。多くの場合、接続参照は、非同期操作の「制御ブロック」として使用されるクラスに格納されます。

于 2010-04-03T16:52:42.680 に答える
1

それぞれに答えるには:

1) はい、できるだけ早く両方を処分することをお勧めします。

2)using()同じ順序で互いにラップされた 2 つのブロックを作成します。最初に内側のオブジェクト (リーダー) を破棄し、次に (接続を使用して) 外側からオブジェクトを破棄します。

于 2010-04-03T16:14:56.700 に答える
0

おそらく、この記事はあなたにとって興味深いものになるでしょう: IDisposable とファイナライザーを実装する方法: 3 つの簡単なルール

于 2010-04-03T16:34:25.120 に答える