如何在多个 C# 调用中使用临时表

问题描述 投票:0回答:6

我有一个 C# 应用程序,使用 ADO.Net 连接到 MSSQL

我需要创建表(具有动态的列数),然后插入许多记录,然后从表中执行选择操作。

每个步骤都必须是单独的 C# 调用,尽管我可以在持续时间内保持连接/事务打开。

c# sql temp-tables
6个回答
8
投票

问题是#Temp 表仅存在于连接和执行范围内。 当从 C# 对 SQL 的第一次调用完成时,控制权将传递到更高级别的范围。

这就像您有一个调用两个存储过程的 T-SQL 脚本一样。每个 SP 创建一个名为#MyTable 的表。第二个 SP 引用的表与第一个 SP 完全不同。
但是,如果父 T-SQL 代码创建了该表,则两个 SP 都可以看到该表,但彼此看不到对方。

这里的解决方案是使用##Temp 表。它们跨越范围和联系。 但危险在于,如果您使用硬编码名称,那么同时运行的程序的两个实例可能会看到同一个表。因此,动态地将表名称设置为始终唯一的名称。


6
投票

SQL Server中有两种类型的临时表,本地临时表和全局临时表。来自 BOL:

在本地临时表名称前添加单个数字符号 (#tablename),并在全局临时表名称前添加两个数字符号 (##tablename)。

本地临时表将仅适用于您当前的连接。全局变量将可用于所有连接。因此,如果您在相关调用中重复使用(并且您确实说过可以)相同的连接,则可以只使用本地临时表,而不必担心同时进程会干扰彼此的临时表。 您可以从

BOL 文章获取更多信息,特别是在“临时表”部分的中间位置。


1
投票

http://martinfowler.com/eaaCatalog/repository.html

问题的其他方面将由标准 sql 处理,您可以在其中动态创建表、插入表、删除表等。这里棘手的部分是使一个事务远离另一个事务。您可能会考虑使用临时表...或者您可能只是有一个专门用于执行此动态表概念的第二个数据库。


1
投票

以下测试方法通过,证明#temp表内容在执行之间仍然存在。

这可能比使用双磅临时表更好,因为 ##temp 表是全局对象。如果您有多个客户端恰好使用相同的 ##temp 表名称,那么它们可能会互相踩踏。此外,##temp 表不会在服务器重新启动后继续存在,因此从技术上讲,它们的生命周期并不是永远的。恕我直言,最好控制#temp 表的范围,因为它们是有限的。

using System.Transactions; using Dapper; using Microsoft.Data.SqlClient; using IsolationLevel = System.Data.IsolationLevel; namespace TestTempAcrossConnection { [TestClass] public class UnitTest1 { private string _testDbConnectionString = @"Server=(localdb)\mssqllocaldb;Database=master;trusted_connection=true"; 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(); Assert.AreEqual(1, tableResult[0].Col1); Assert.AreEqual("one", tableResult[0].Col2); tran.Commit(); } [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(); Assert.AreEqual(2, tableResult[1].Col1); Assert.AreEqual("two", tableResult[1].Col2); scope.Complete(); } } }



0
投票


0
投票
非参数化

查询创建临时表(!),那么该表将在后续命令期间持续存在(只要连接保持打开状态) cn.Execute(@"CREATE TABLE #TempTbl (ID int)"); //no parameters in the SQL cn.Execute(@"INSERT INTO #TempTbl (ID) VALUES (@param1)"); //table is still there!

原因是参数化查询通过
sp_executesql

(又名

CommandType.StoredProcedure
)使用batchRpc模式,这缩小了范围。虽然非参数查询是通过普通的
CommendType.Text
直接执行的,这避免了嵌套范围。
    

© www.soinside.com 2019 - 2024. All rights reserved.