@エド・ギネス
(これは古いスレッドであることは知っていますが、将来これが必要になる可能性のある人のために)
;tldr 回答: いくつかのコード変更がないわけではありません (ほとんどの場合、非破壊的で合理的な変更 IMHO )。
接続オブジェクトが開かれると、Microsoft が SPID を公開しないのは非常に奇妙です。たとえば、SPID ではなく SqlConnection オブジェクトから取得できる SQL バージョン名やその他の SQL Server 固有のプロパティを確認できます。
詳細:
すべての SQLConnection には 1 つの SPID が割り当てられます。これは T-SQL コマンド @@SPID を使用して取得されますが、これは SQL Server 側で実行されます。トリックは、SQL Server 側で行われている主な作業と共にそれを渡し、C# 側で読み取ることです。
SPID が必要となる可能性のある 4 つのシナリオ。
- 結果セットを返すストアド プロシージャを実行しています (spid を除く)
- INS/UPD/DEL ストアド プロシージャを実行しています。
- CRUD操作を行うために、ADO.Netからオンザフライ(インライン)でPrepared SQL stmsを実行しています(yikes!!)(つまり、ストアドプロシージャなしのシナリオ1および2)
- 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 を選択します。
それでおしまい 。それが誰かを助けることを願っています。