我有一个 C# 应用程序,使用 ADO.Net 连接到 MSSQL
我需要创建表(具有动态列数),然后插入许多记录,然后从表中进行选择。
每个步骤都必须是一个单独的 C# 调用,尽管我可以在此期间保持连接/事务打开。
我有一个 C# 应用程序,使用 ADO.Net 连接到 MSSQL
我需要创建表(具有动态列数),然后插入许多记录,然后从表中进行选择。
每个步骤都必须是一个单独的 C# 调用,尽管我可以在此期间保持连接/事务打开。
问题是#Temp 表仅存在于连接和执行范围内。当从 C# 到 SQL 的第一次调用完成时,控制权传递到更高级别的范围。
这就像您有一个调用两个存储过程的 T-SQL 脚本一样。每个 SP 都创建了一个名为#MyTable 的表。第二个 SP 引用的表与第一个 SP 完全不同。
但是,如果父 T-SQL 代码创建了表,则两个 SP 都可以看到它,但彼此看不到。
这里的解决方案是使用##Temp 表。它们跨越范围和联系。但危险在于,如果您使用硬编码名称,那么同时运行的程序的两个实例可能会看到同一张表。因此,动态地将表名设置为始终唯一的名称。
SQL Server 中有两种临时表,本地临时表和全局临时表。来自 BOL:
本地临时表名称前缀为单号 (#tablename),全局临时表名称前缀为双号 (##tablename)。
本地临时表仅适用于您当前的连接。全局变量将可用于所有连接。因此,如果您在相关调用中重复使用(并且您确实说过可以)相同的连接,您可以只使用本地临时表,而不必担心同时进程会干扰彼此的临时表。
您可以从BOL 文章中获得更多信息,特别是在大约一半的“临时表”部分下。
就在 C# 中处理这个概念而言,您可以查看存储库模式。这允许您拥有一个用于数据访问的低级别存储库层,其中每个方法执行一个任务。但是连接被传递给方法,并且实际操作是在事务范围内执行的。这意味着理论上您可以在数据访问层(作为存储库实现)中调用许多不同的方法,如果其中任何一个方法失败,您可以回滚整个操作。
http://martinfowler.com/eaaCatalog/repository.html
您问题的其他方面将由标准 sql 处理,您可以在其中动态创建表、插入表、从中删除等。这里棘手的部分是使一个事务远离另一个事务。您可能希望使用临时表......或者您可能只是有一个专门用于执行此动态表概念的第二个数据库。
就我个人而言,我认为您正在以艰难的方式做到这一点。在一个存储过程中执行所有步骤。
延长单磅符号#Temp 的范围/寿命的一种方法是使用事务。下面我使用的是 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();
}