3

我可以使用 GetHashCode() 来识别对象,但是有什么方法可以识别 SqlConnection 对象获得的实际 sql 连接?

我(仍在)尝试调试涉及池连接和应用程序角色的问题,如果我能够可靠地识别底层 sql 连接,它会很有帮助。

这是一些可能说明问题的代码

SqlConnection c = new SqlConnection(myConnString);

c.Open();  // GetHashCode == "X"

c.Close(); // returns connection to pool

c.Open;  // GetHashCode() == "X" but possibly different pooled connection?

当我写这个问题时,我突然想到我可能想要的是连接的 SPID。可悲的是,由于我试图解决的错误,当 SQL 删除连接时,SPID 不可用(所以在我最感兴趣的时候,我无法在该连接上运行命令来获取 SPID) .

还有什么好主意吗?

4

6 回答 6

3

@埃德吉尼斯,

(我知道这是一个旧线程,但为了将来可能需要它的人的利益)

;tldr 回答:并非没有一些代码更改(主要是非破坏性和合理的更改恕我直言)。

非常奇怪的是,一旦打开连接对象,Microsoft 就不会公开 SPID。例如,我可以看到可以从 SqlConnection 对象而不是 SPID 获得的 SQL 版本名称和其他 SQL Server 特定属性。

细节:

每个 SQLConnection 都分配有一个 SPID。这是使用 T-SQL 命令@@SPID 获得的,但这在 SQL Server 端执行。诀窍是将它与在 SQL Server 端完成的主要工作一起传递,并在 C# 端读取它。

需要 SPID 的四种可能情况。

  1. 您正在执行一个返回结果集的存储过程(减去 spid)
  2. 您正在执行 INS/UPD/DEL 存储过程。
  3. 您正在从 ADO.Net (yikes!!) 运行 Prepared SQL stms On the fly (inline) 来执行 CRUD 操作(即没有存储过程的场景 1 和 2)
  4. 您正在使用 SqlBulkCopy 将数据直接插入到表中

1. 返回结果集的存储过程

假设您有一个从主数据库返回行的 SP (USP_GetDBDetails)。我们需要在 Existing SQL Stmt 中添加一行代码来返回 SPID 并在 C# 端使用 Paramter 类型获取它以检索 ReturnValue。也可以读取主要的结果集。

存储过程是一个美丽的东西。它们可以同时返回一个返回值和一个结果集和一个输出参数。在这种情况下,在 SP 端,我们只需要在 ADO.Net 使用 SqlConnection 执行的 SP 的末尾添加额外的返回值。我们这样做如下面的 T-SQL 代码所示:

CREATE Procedure [dbo].[USP_GetDBDetails] 
AS
BEGIN

    SELECT 
            database_id,
            name,
            create_date         
      FROM  [sys].[databases]

      Return @@SPID -- Line of Code that needs to be added to return the SPID

END

现在在 C# 端捕获 SPID(根据需要修改连接字符串):

        using (SqlConnection conn = new SqlConnection(@"Data Source=(local);Initial Catalog=master;Persist Security Info=True;Integrated Security =SSPI;"))
        {

            string strSql = "USP_GetDBDetails";

            SqlCommand sqlcomm = new SqlCommand();
            sqlcomm.CommandText = strSql;
            sqlcomm.CommandType = CommandType.StoredProcedure;
            sqlcomm.Connection = conn;

            SqlParameter returnValueParam = sqlcomm.Parameters.Add("@ReturnValue", SqlDbType.Int);
            returnValueParam.Direction = ParameterDirection.ReturnValue;

            conn.Open();

**// Reader Section**
            SqlDataReader rdr = sqlcomm.ExecuteReader();
            DataTable dt = new DataTable();
            dt.Load(rdr); // Get the Reultset into a DataTable so we can use it !
            rdr.Close();  // Important to close the reader object before reading the return value.

// Lets get the return value which in this case will be the SPID for this connection.
           string spid_str = returnValueParam.Value.ToString();
           int spid = (int)sqlcomm.Parameters["@ReturnValue"].Value; // Another Way to get the return value.

           Console.WriteLine("SPID For this Conn = {0} ", spid);

// To use the Reult Sets that was returned by the SP:

        foreach (DataRow dr in dt.Rows)
        {
            string dbName = dr["Name"].ToString();
            // Code to use the Other Columns goes here

        }
      }

输出 :

SPID For this Conn = 66

2.如果Connection对象正在执行一个处理INS/UPS/DEL的SP

就像我们在场景 1 中所做的那样,在负责 INS/UPD/DEL 的 SP 的末尾添加 RETURN @@SPID。

在 C# 端获取 SPID .. 一切都与场景 1 中的相同,除了阅读器部分。删除 Reader Section 下的 4 行,并用下面的这一行替换。(显然,迭代 DataTable dt 的 foreach 循环不是必需的)

sqlcomm.ExecuteNonQuery();

3. INS/UPD/DEL 使用内联 SQL

将这些 stmts 移动到存储过程中并按照场景 2 的步骤进行操作。可能有一些方法可以做一些 T-SQL 杂技来注入 @@SPID 并通过可能使用 MultipleActiveResultSets 选项返回它,但不是很优雅的 IMO。


4. SqlBulkCopy

这将需要查询表以获取 spid。由于没有存储过程可以从 SqlServer 返回可以捕获的 SPID。

我们需要添加一个额外的 INT 类型列来保存 SPID 值,如下所示:

ALTER TABLE dbo.TBL_NAME ADD
    SPID int NOT NULL Default( @@SPID )
GO

通过这样做,SQL Server 将自动将 SPID 值插入到新添加的列中。在处理 BulkCopy 的 C# ADO 端不需要更改代码。典型的 Bulkcopy ADO 代码如下所示,它应该在上面的 ALTER TABLE Stmt 之后继续工作。

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();

            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
            {

            DataTable dt = new DataTable();
            dt.Columns.Add("Col1");
            dt.Columns.Add("Col2");

            string[] row = { "Col1Value", "Col2Value" };

            dt.Rows.Add(row);
                bulkCopy.DestinationTableName = "TBL_NAME_GOES_HERE"; //TBL_NAME

                try
                {
                    // Write from the source to the destination.
                    bulkCopy.WriteToServer(dt);
                }
                catch (SqlException ex)
                {

                  // Handle Exception

                }
            }
     }

因此,要检查输出,请从 dbo.TBL_NAME 中选择不同的 SPID

就是这样 。希望对某人有所帮助。

于 2016-07-02T23:52:25.430 回答
1

您可以在连接字符串中设置应用程序名称,然后在 SQL Server 中可见。通常它默认为 SQL 客户端,但您可以覆盖:

"Integrated Security=true;Initial Catalog=Northwind;server=(local);Application Name=MyKeyword"

此属性可以由 SqlConnection 实例的 ConnectionString 属性读回。

编辑:正如 edg 所指出的,连接字符串定义了哪个连接池,所以这可能不起作用。

于 2009-02-20T14:49:22.167 回答
1

并不是说这是不可能的,但我还没有找到任何方法来做到这一点。

于 2009-10-21T15:25:09.103 回答
0

不是一个直接的答案,而是你应该注意的一些事情。对象的哈希码在其整个生命周期内不应更改。如果是这样,那么您可以将一个对象放入散列集合中,更改它的散列码,然后无法再次从集合中检索它。

如果您附加一个调试器并查看私有字段,您不能打开某种内部标识符吗?如果是这样,如果需要,您可以在调试期间通过反射访问它。

于 2009-02-20T14:20:29.303 回答
0

如果我正确理解您的问题,理查德的回答对您没有帮助,因为您正在寻找底层 .NET 连接池中的实际对象。我也不相信哈希会有所帮助,因为您正在查看基础池。

我没有答案,本身,而是一个建议。获取 Reflector(现在是 RedGate 产品)的副本并通过 System.Data.DLL 并查看事物是如何存储在底层池中的。我不确定它会给你一个快速而简单的答案,但如果有任何事情你可以反思以获得帮助调试你的问题的答案,它就会在那里。

顺便说一句,您要解决的错误是什么?

于 2009-02-22T23:14:32.077 回答
0

您可以尝试的一件事是

SqlConnection.ClearPool();

或者

SqlConnection.ClearAllPools();

看看您是否可以隔离您面临的任何问题。

于 2009-02-22T23:17:02.070 回答