Идентификация базового соединения sql объекта SqlConnection - PullRequest
1 голос
/ 20 февраля 2009

Я могу использовать GetHashCode () для идентификации объекта, но есть ли способ идентифицировать фактическое соединение SQL, полученное объектом SqlConnection?

Я (все еще) пытаюсь отладить проблему, связанную с пулированными соединениями и ролями приложений, и если бы я мог надежно определить базовое соединение 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 соединения. К сожалению, SPID недоступен, когда SQL-соединение обрывается из-за ошибки, которую я пытаюсь устранить (поэтому в данный момент меня больше всего интересует, я не могу выполнить команду для этого соединения для получения SPID) .

Какие-нибудь другие яркие идеи?

Ответы [ 6 ]

2 голосов
/ 03 июля 2016

@ Эд Гиннес,

(я знаю, что это старая ветка, но для тех, кому это может понадобиться в будущем)

; tldr answer: Не обошлось без некоторых изменений кода (в основном это неразрывные и разумные изменения IMHO).

Очень странно, что Microsoft не раскрывает SPID после открытия объекта подключения. Например, я вижу имя версии SQL и другие специфические свойства SQL Server, которые можно получить из объекта SqlConnection, но не из SPID.

подробности:

Каждому SQLConnection назначается один SPID. Это получается с помощью команды T-SQL @@ SPID, но выполняется на стороне SQL Server. Хитрость заключается в том, чтобы передать это вместе с основной работой, выполняемой на стороне SQL Server, и прочитать ее на стороне C #.

Четыре возможных сценария, для которых требуется SPID.

  1. Вы выполняете хранимую процедуру, которая возвращает набор результатов (минус спид)
  2. Вы делаете INS / UPD / DEL хранимой процедурой.
  3. Вы выполняете подготовленные SQL-сообщения на лету (встроенные) из ADO.Net (да!
  4. Вы вставляете данные непосредственно в таблицу с помощью SqlBulkCopy

1. Хранимая процедура, которая возвращает набор результатов

Допустим, у вас есть SP (USP_GetDBDetails), который возвращает строки из главной базы данных. Нам нужно добавить строку кода в существующий SQL Stmt, чтобы вернуть SPID и получить его на стороне C #, используя тип Paramter для получения ReturnValue. Основные Resultsets также могут быть прочитаны.

Хранимые процедуры - прекрасная вещь. Они могут одновременно возвращать возвращаемое значение И набор результатов И параметр OutPut. В этом случае на стороне SP нам нужно только добавить дополнительное возвращаемое значение в конце SP, который выполняется ADO. Сеть с использованием SqlConnection. Мы делаем это, как показано в коде 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

Теперь для захвата SPID на стороне C # (при необходимости измените строку подключения):

        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 выполняет SP, который обрабатывает INS / UPS / DEL

Добавьте RETURN @@ SPID в конце SP, который отвечает за INS / UPD / DEL, так же, как мы это делали для сценария 1.

И на стороне C # для получения SPID .. все остается таким же, как в Сценарии 1, за исключением секции чтения . Удалите 4 строки в разделе Reader и замените эту строку ниже. (и, очевидно, цикл foreach для итерации DataTable dt не понадобится)

sqlcomm.ExecuteNonQuery();

3. INS / UPD / DEL с использованием встроенного SQL

Переместите эти stmts в хранимую процедуру и выполните шаги для сценария 2. Могут быть способы сделать некоторую акробатику T-SQL, чтобы внедрить @@ SPID и вернуть его, возможно, используя опцию MultipleActiveResultSets, но не очень Elegant IMO.


4. SqlBulkCopy .

Для этого потребуется запросить таблицу, чтобы получить спид. Поскольку нет хранимой процедуры для возврата SPID из SqlServer, который можно перехватить.

Нам нужно добавить дополнительный столбец типа INT для хранения значения SPID следующим образом:

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

При этом SQL Server автоматически вставит значение SPID во вновь добавленный столбец. Никакого изменения кода не потребуется на стороне C # ADO, которая обрабатывает BulkCopy. Типичный код Bulkcopy ADO выглядит следующим образом, и он должен продолжать работать после команды ALTER TABLE, указанной выше.

        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

                }
            }
     }

Таким образом, чтобы проверить вывод, выберите отдельный идентификатор SPID из dbo.TBL_NAME

Вот и все. Надеюсь, это кому-нибудь поможет.

1 голос
/ 20 февраля 2009

Вы можете установить имя приложения в строке подключения, это будет видно в SQL Server. Обычно это значение по умолчанию для клиента SQL, но вы можете переопределить:

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

Это свойство может быть прочитано обратно свойством ConnectionString экземпляра SqlConnection.

Редактировать: Как отмечает edg, строка подключения определяет, какой пул соединений, так что это, вероятно, не будет работать.

0 голосов
/ 21 октября 2009

Не скажу, что это невозможно, но я пока не нашел способа сделать это.

0 голосов
/ 23 февраля 2009

Одна вещь, которую вы можете попробовать, это

SqlConnection.ClearPool();

или

SqlConnection.ClearAllPools();

чтобы узнать, можете ли вы выделить какие-либо проблемы, с которыми вы столкнулись.

0 голосов
/ 23 февраля 2009

Ответ Ричарда не поможет вам, если я правильно понимаю вашу проблему, поскольку вы ищете фактический объект в базовом пуле соединений .NET. Я также не уверен, что хеш поможет, поскольку вы смотрите на основной пул.

У меня нет ответа, как такового, но есть предложение. Получите копию Reflector (теперь это продукт RedGate), пройдите System.Data.DLL и посмотрите, как все хранится в базовом пуле. Я не уверен, что он даст вам быстрый и простой ответ, но если есть что-то, о чем вы можете подумать, чтобы получить ответ, чтобы помочь отладить вашу проблему, он будет там.

Кстати, что за ошибку вы пытаетесь устранить?

0 голосов
/ 20 февраля 2009

Не прямой ответ, но то, что вы должны отметить. Хеш-код объекта не должен изменяться в течение всей его жизни. Если это так, то вы можете поместить объект в хешированную коллекцию, изменить его хеш-код, а затем снова не сможете извлечь его из коллекции.

Если вы присоединяете отладчик и просматриваете приватные поля, не можете ли вы включить какой-нибудь внутренний идентификатор? Если это так, вы можете получить доступ к нему через рефлексию во время отладки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...