使用dapper,为什么在一次使用连接时创建的临时表在第二次使用同一连接时不可用

Bob*_*son 9 c# sql temp-tables dapper

我正在尝试使用C#中的dapper执行一系列SQL*Server步骤.一步创建临时表并填充它.以下步骤从临时表中查询数据.create/populate似乎运行成功,但临时表中的第一个查询失败说:

"无效的对象名称'#GetPageOfGlobalUsers'."

        using (SqlConnection connection = DBConnectionProvider.CreateConnection())
        {
            ... misc setup stuff...

            connection.Execute(@"
                create table #GetPageOfGlobalUsers(row int, EmailAddress nvarchar(max), LastName nvarchar(max), FirstName nvarchar(max), Id uniqueidentifier)
                insert into #GetPageOfGlobalUsers
                SELECT ROW_NUMBER() OVER (order by LastName, FirstName, EmailAddress) row,
                    EmailAddress, LastName, FirstName, Id 
                    FROM Users 
                    WHERE LastName like @search or FirstName like @search or EmailAddress like @search
            ", new { search = search }
            );

            int count = connection.Query<int>(@"
                SELECT count(*) from tempdb..#GetPageOfGlobalUsers
            ").Single<int>();

... more queries from the temp table follow
Run Code Online (Sandbox Code Playgroud)

上面,执行工作,但查询失败,上面提到的错误.(请注意,无论是否使用"tempdb .."前缀,我都会得到相同的错误.)如果我创建一个永久表(即,如果我删除了前导哈希)或者如果我将它设为全局临时表(即前缀)两个哈希的名字)一切正常.

我的理解是,使用单个哈希命名的临时表的范围是连接的持续时间,所以我不知道发生了什么.但我相信有人可以告诉我!

(顺便说一句,如果没有人告诉我"不要这样做",我会很感激,除非它根本无法完成.)

Bob*_*son 7

我不知道到底发生了什么,但我能够通过在自己的执行中创建临时表来解决问题,而不是在执行中创建表并填充它,如代码中所示在我的问题中显示.

也就是说,以下工作:

            connection.Execute(@"
                create table #PagesOfUsers(row int, 
                                           EmailAddress nvarchar(max), 
                                           LastName nvarchar(max), 
                                           FirstName nvarchar(max), 
                                           Id uniqueidentifier)"
                );

            connection.Execute(@"
                insert into #PagesOfUsers
                SELECT ROW_NUMBER() OVER (order by LastName, FirstName, EmailAddress) row,
                    EmailAddress, LastName, FirstName, Id 
                    FROM Users 
                    WHERE LastName like @search or FirstName like @search or EmailAddress like @search
            ", new { search = search }
            );

            int count = connection.Query<int>(@"
                SELECT count(*) from #PagesOfUsers
            ").Single<int>();
Run Code Online (Sandbox Code Playgroud)

这并不可怕,但不方便.值得注意的是,我根本不必显式创建临时表.实际上,我最初将create/populate操作编码为SELECT INTO,因此我不必逐条列出临时表的列.但是这也在后续查询中遇到了"无效对象"错误,因此我尝试使用显式CREATE TABLE来查看它是否有所不同,并在发现它没有发现我的问题.

我看到的行为是,当创建临时表并在同一个Execute中填充时,它在Execute结束后确实不在tempdb中,表面上是成功的.这让我想知道我的原始代码中的Execute是否正在做任何事情!据我所知,这相当于一个NOOP.

  • 我发现这个原因与这里找到的答案有关:/sf/answers/464298621/ 当您在命令中包含参数时,.net 使用“exec sp_executesql”调用包装您的 sql,这使得您的临时表只能在该上下文中访问。如果不包含参数,则直接执行您的sql,因此可用于后续命令。 (4认同)

Mar*_*ell 6

我怀疑连接没有打开.如果是这样,dapper将根据需要打开和关闭(返回池)连接.这将重置连接,丢失命令之间的任何临时表.

只需明确打开连接.