ADO.Netを使用してMSSQLに接続するC#アプリケーションがあります
(動的な列数で)テーブルを作成し、多数のレコードを挿入してから、テーブルから選択を戻す必要があります。
各ステップは個別のC#呼び出しである必要がありますが、その間、接続/トランザクションを開いたままにしておくことができます。
ADO.Netを使用してMSSQLに接続するC#アプリケーションがあります
(動的な列数で)テーブルを作成し、多数のレコードを挿入してから、テーブルから選択を戻す必要があります。
各ステップは個別のC#呼び出しである必要がありますが、その間、接続/トランザクションを開いたままにしておくことができます。
SQL Serverには、ローカル一時テーブルとグローバル一時テーブルの2種類の一時テーブルがあります。BOLから:
ローカルの一時テーブル名の前に単一の番号記号(#tablename)を付け、グローバルの一時テーブル名の前に二重の番号記号(## tablename)を付けます。
ローカル一時テーブルは、現在の接続に対してのみ有効です。グローバルはすべての接続で利用できます。したがって、関連する呼び出し間で同じ接続を再利用する場合(そして可能だと言った場合)、同時プロセスが互いの一時テーブルに干渉することを心配せずに、ローカルの一時テーブルを使用できます。
これについての詳細は、 BOLの記事、特に「一時的なテーブル」セクションの途中で入手できます。
問題は、#Tempテーブルが接続と実行のスコープ内にのみ存在することです。C#からSQLへの最初の呼び出しが完了すると、制御はより高いレベルのスコープに渡されます。
これは、2つのストアドプロシージャを呼び出すT-SQLスクリプトがある場合と同じです。各SPは、#MyTableという名前のテーブルを作成しました。2番目のSPは、最初のSPとは完全に異なるテーブルを参照しています。
ただし、親T-SQLコードがテーブルを作成した場合、両方のSPはテーブルを表示できますが、お互いを表示することはできません。
ここでの解決策は、##Tempテーブルを使用することです。それらはスコープと接続を横断します。ただし、ハードコードされた名前を使用すると、同時に実行されているプログラムの2つのインスタンスが同じテーブルを参照する可能性があるという危険性があります。したがって、テーブル名を常に一意になる名前に動的に設定します。
C#でこの概念を扱う限り、リポジトリパターンを見ることができます。これにより、各メソッドがタスクを実行するデータアクセス用の低レベルのリポジトリレイヤーを作成できます。ただし、接続はメソッドに渡され、実際のアクションはトランザクションスコープで実行されます。つまり、理論的には、データアクセス層(リポジトリとして実装)でさまざまなメソッドを呼び出すことができ、それらのいずれかが失敗した場合は、操作全体をロールバックできます。
http://martinfowler.com/eaaCatalog/repository.html
質問の他の側面は、テーブルを動的に作成したり、テーブルに挿入したり、テーブルから削除したりできる標準SQLによって処理されます。ここで注意が必要なのは、あるトランザクションを別のトランザクションから遠ざけることです。一時テーブルの使用を検討する場合もあれば、この動的テーブルの概念を実行するための2番目のデータベースがある場合もあります。
個人的に私はあなたがこれを難しい方法でやっていると思います。1つのストアドプロシージャですべての手順を実行します。
単一ポンド記号#Tempの範囲/寿命を延長する1つの方法は、トランザクションを使用することです。以下ではDapperを使用していますが、トランザクションが#tempテーブルをどのように維持するかを理解できます。
class TestTable1
{
public int Col1 { get; set; }
public string Col2 { get; set; }
}
[TestMethod]
public void TempTableBetweenExecutionsTest()
{
using var conn = new SqlConnection(_testDbConnectionString);
conn.Open();
var tran = conn.BeginTransaction(IsolationLevel.ReadCommitted);
conn.Execute("create table #test1(col1 int, col2 varchar(20))", transaction:tran);
conn.Execute("insert into #test1(col1,col2) values (1, 'one'),(2,'two')", transaction: tran);
var tableResult = conn.Query<TestTable1>("select col1, col2 from #test1",transaction:tran).ToList();
tran.Commit();
}
また、TransactionScopeはバックグラウンドでアンビエントトランザクションを作成するため、TransactionScopeでも同じ効果が得られます。
[TestMethod]
public void TempTableBetweenExecutionsScopeTest()
{
using var scope = new TransactionScope();
using var conn = new SqlConnection(_testDbConnectionString);
conn.Open();
conn.Execute("create table #test1(col1 int, col2 varchar(20))");
conn.Execute("insert into #test1(col1,col2) values (1, 'one'),(2,'two')");
var tableResult = conn.Query<TestTable1>("select col1, col2 from #test1").ToList();
scope.Complete();
}