3

GetHashCode() を使用してオブジェクトを識別できますが、SqlConnection オブジェクトによって取得された実際の SQL 接続を識別する方法はありますか?

私は (まだ) プールされた接続とアプリケーション ロールに関連する問題をデバッグしようとしています。基礎となる SQL 接続を確実に特定できれば、大いに役立つでしょう。

質問を説明するコードを次に示します

SqlConnection c = new SqlConnection(myConnString);

c.Open();  // GetHashCode == "X"

c.Close(); // returns connection to pool

c.Open;  // GetHashCode() == "X" but possibly different pooled connection?

この質問を書いていると、おそらく必要なのは接続の SPID であることがわかります。悲しいことに、解決しようとしているバグが原因で SQL によって接続が切断された場合、SPID は使用できません (そのため、最も関心のある時点で、その接続でコマンドを実行して SPID を取得することはできません)。 .

他に明るいアイデアはありますか?

4

6 に答える 6

3

@エド・ギネス

(これは古いスレッドであることは知っていますが、将来これが必要になる可能性のある人のために)

;tldr 回答: いくつかのコード変更がないわけではありません (ほとんどの場合、非破壊的で合理的な変更 IMHO )。

接続オブジェクトが開かれると、Microsoft が SPID を公開しないのは非常に奇妙です。たとえば、SPID ではなく SqlConnection オブジェクトから取得できる SQL バージョン名やその他の SQL Server 固有のプロパティを確認できます。

詳細:

すべての SQLConnection には 1 つの SPID が割り当てられます。これは T-SQL コマンド @@SPID を使用して取得されますが、これは SQL Server 側で実行されます。トリックは、SQL Server 側で行われている主な作業と共にそれを渡し、C# 側で読み取ることです。

SPID が必要となる可能性のある 4 つのシナリオ。

  1. 結果セットを返すストアド プロシージャを実行しています (spid を除く)
  2. INS/UPD/DEL ストアド プロシージャを実行しています。
  3. CRUD操作を行うために、ADO.Netからオンザフライ(インライン)でPrepared SQL stmsを実行しています(yikes!!)(つまり、ストアドプロシージャなしのシナリオ1および2)
  4. SqlBulkCopy を使用してデータをテーブルに直接挿入しています

1. 結果セットを返すストアド プロシージャ

マスター データベースから行を返す SP (USP_GetDBDetails) があるとします。SPID を返すコード行を既存の SQL Stmt に追加し、ReturnValue を取得するために Paramter 型を使用して C# 側で取得する必要があります。メインの結果セットも読み取ることができます。

ストアド プロシージャは美しいものです。これらは、戻り値と結果セットと OutPut パラメータを同時に返すことができます。この場合、SP 側では、SqlConnection を使用して ADO.Net によって実行されている SP の最後に追加の戻り値を追加するだけで済みます。以下の T-SQL コードに示すようにこれを行います。

CREATE Procedure [dbo].[USP_GetDBDetails] 
AS
BEGIN

    SELECT 
            database_id,
            name,
            create_date         
      FROM  [sys].[databases]

      Return @@SPID -- Line of Code that needs to be added to return the SPID

END

次に、C# 側で SPID を取得します (必要に応じて接続文字列を変更します)。

        using (SqlConnection conn = new SqlConnection(@"Data Source=(local);Initial Catalog=master;Persist Security Info=True;Integrated Security =SSPI;"))
        {

            string strSql = "USP_GetDBDetails";

            SqlCommand sqlcomm = new SqlCommand();
            sqlcomm.CommandText = strSql;
            sqlcomm.CommandType = CommandType.StoredProcedure;
            sqlcomm.Connection = conn;

            SqlParameter returnValueParam = sqlcomm.Parameters.Add("@ReturnValue", SqlDbType.Int);
            returnValueParam.Direction = ParameterDirection.ReturnValue;

            conn.Open();

**// Reader Section**
            SqlDataReader rdr = sqlcomm.ExecuteReader();
            DataTable dt = new DataTable();
            dt.Load(rdr); // Get the Reultset into a DataTable so we can use it !
            rdr.Close();  // Important to close the reader object before reading the return value.

// Lets get the return value which in this case will be the SPID for this connection.
           string spid_str = returnValueParam.Value.ToString();
           int spid = (int)sqlcomm.Parameters["@ReturnValue"].Value; // Another Way to get the return value.

           Console.WriteLine("SPID For this Conn = {0} ", spid);

// To use the Reult Sets that was returned by the SP:

        foreach (DataRow dr in dt.Rows)
        {
            string dbName = dr["Name"].ToString();
            // Code to use the Other Columns goes here

        }
      }

出力:

SPID For this Conn = 66

2. Connection オブジェクトが INS/UPS/DEL を処理する SP を実行している場合

シナリオ 1 で行ったように、INS/UPD/DEL を担当する SP の末尾に RETURN @@SPID を追加します。

SPID を取得するための C# 側では、リーダー セクションを除いて、すべてシナリオ 1 と同じままです。Reader セクションの下の 4 行を削除し、以下の行に置き換えます。(そして明らかに、DataTable dt を反復するための foreach ループは必要ありません)

sqlcomm.ExecuteNonQuery();

3. インライン SQL を使用した INS/UPD/DEL

これらのステートメントをストアド プロシージャに移動し、シナリオ 2 の手順に従います。T-SQL アクロバットを実行して @@SPID を挿入し、おそらく MultipleActiveResultSets オプションを利用してそれを返す方法があるかもしれませんが、あまりエレガントな IMO ではありません。


4. SqlBulkCopy

これには、テーブルをクエリして spid を取得する必要があります。キャプチャできる SqlServer から SPID を返すストアド プロシージャがないためです。

次のように、SPID 値を保持するために INT 型の列を追加する必要があります。

ALTER TABLE dbo.TBL_NAME ADD
    SPID int NOT NULL Default( @@SPID )
GO

これにより、SQL Server は SPID 値を新しく追加された列に自動的に挿入します。BulkCopy を処理する C# ADO 側でコードを変更する必要はありません。典型的な Bulkcopy ADO コードは以下のようになり、上記の ALTER TABLE Stmt の後も引き続き機能するはずです。

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();

            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
            {

            DataTable dt = new DataTable();
            dt.Columns.Add("Col1");
            dt.Columns.Add("Col2");

            string[] row = { "Col1Value", "Col2Value" };

            dt.Rows.Add(row);
                bulkCopy.DestinationTableName = "TBL_NAME_GOES_HERE"; //TBL_NAME

                try
                {
                    // Write from the source to the destination.
                    bulkCopy.WriteToServer(dt);
                }
                catch (SqlException ex)
                {

                  // Handle Exception

                }
            }
     }

したがって、出力を確認するには、dbo.TBL_NAME から個別の SPID を選択します。

それでおしまい 。それが誰かを助けることを願っています。

于 2016-07-02T23:52:25.430 に答える
1

これが不可能だとは言いませんが、私はまだそれを行う方法を見つけていません。

于 2009-10-21T15:25:09.103 に答える
1

接続文字列にアプリケーション名を設定すると、これが SQL Server に表示されます。通常は SQL クライアントがデフォルトですが、オーバーライドできます。

"Integrated Security=true;Initial Catalog=Northwind;server=(local);Application Name=MyKeyword"

このプロパティは、SqlConnection インスタンスの ConnectionString プロパティによって読み取ることができます。

編集:edgで指摘されているように、接続文字列は接続プールを定義するため、これはおそらく機能しません。

于 2009-02-20T14:49:22.167 に答える
0

あなたが試すことができる1つのことは

SqlConnection.ClearPool();

また

SqlConnection.ClearAllPools();

直面している問題を特定できるかどうかを確認します。

于 2009-02-22T23:17:02.070 に答える
0

直接的な回答ではありませんが、注意すべき点があります。オブジェクトのハッシュ コードは、その有効期間を通じて変更されるべきではありません。その場合、オブジェクトをハッシュされたコレクションに入れ、そのハッシュ コードを変更すると、コレクションから再度取得できなくなります。

デバッガーをアタッチしてプライベート フィールドを表示すると、ある種の内部識別子を有効にすることはできませんか? もしそうなら、必要に応じてデバッグ中にリフレクションを介してアクセスできます。

于 2009-02-20T14:20:29.303 に答える
0

基礎となる.NET接続プールで実際のオブジェクトを探しているので、私があなたの問題を適切に理解している場合、リチャードの答えは役に立ちません。また、基礎となるプールを見ているので、ハッシュが役立つとは確信していません。

それ自体には答えはありませんが、提案があります。Reflector (現在は RedGate 製品) のコピーを入手し、System.Data.DLL を調べて、基礎となるプールにどのように格納されているかを調べます。迅速かつ簡単な答えが得られるかどうかはわかりませんが、問題のデバッグに役立つ答えを得るために熟考できることがあれば、そこにあるでしょう.

ところで、あなたが解決しようとしているバグは何ですか?

于 2009-02-22T23:14:32.077 に答える