代码之家  ›  专栏  ›  技术社区  ›  Jason Coyne

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

  •  3
  • Jason Coyne  · 技术社区  · 16 年前

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

    5 回复  |  直到 9 年前
        1
  •  6
  •   Funka    16 年前

    问题是#Temp表仅存在于连接和执行范围内。


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

        2
  •  6
  •   John Gilbert    13 年前

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

    在本地临时表名前添加单数字符号(#tablename),在全局临时表名前面添加双数字符号(###tablename)。

    本地温度表将持续使用 您当前的连接。全局变量将可用于所有连接。因此,如果你在相关调用中重用(你确实说过可以)相同的连接,你就可以使用本地临时表,而不用担心同时进行的进程会干扰彼此的临时表。

    BOL article

        3
  •  1
  •   Andrew Siemer    16 年前

    在C#中处理这个概念时,您可以看看存储库模式。这允许您拥有一个用于数据访问的低级存储库层,其中每个方法都执行一个任务。但是,连接被传递给方法,实际操作在事务范围内执行。这意味着您理论上可以在数据访问层(实现为存储库)中调用许多不同的方法,如果其中任何一个方法失败,您可以回滚整个操作。

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

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

        4
  •  0
  •   HLGEM    16 年前

        5
  •  0
  •   Larry Smith    5 年前

    扩展单磅符号#Temp的范围/生命周期的一种方法是使用事务。只要事务存在,#temp表就会继续存在。您还可以使用TransactionScope来获得相同的效果,因为TransactionScope在后台创建环境事务。

    这可能比使用双磅临时表更可取,因为##临时表是全局对象。如果您有多个客户端碰巧使用相同的##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();
           }
       }
    }