Достъп до съобщенията на SQL Server чрез ADO.NET

Възможно ли е достъп до „съобщенията за странични продукти“ на SQL Server чрез ADO.NET? Поради липсата на думи, под „съобщения за странични продукти“ имам предвид изхода, който се появява в раздела Съобщения в Microsoft SQL Server Management Studio. Това, което особено имам предвид, е да прочета резултата от SET STATISTICS TIME ON. Изглежда, че SqlDataReader не предлага нищо по този въпрос.


person Jan Zich    schedule 19.04.2009    source източник


Отговори (3)


Да, има събитие в класа SqlConnection, наречено SqlInfoMessage, към което можете да се свържете:

SqlConnection _con = 
   new SqlConnection("server=.;database=Northwind;integrated Security=SSPI;");

_con.InfoMessage += new SqlInfoMessageEventHandler(InfoMessageHandler);

Манипулаторът на събитие ще изглежда така:

static void InfoMessageHandler(object sender, SqlInfoMessageEventArgs e)
{
    string myMsg = e.Message;            
}

e.Message е съобщението, отпечатано в прозореца за съобщения в SQL Server Management Studio.

person marc_s    schedule 19.04.2009
comment
+1 за това. Беше под носа ми в ADO (OnInfoMessage) повече от десетилетие; просто никога не съм оценявал това, което беше. - person Ian Boyd; 04.02.2012
comment
Това постижимо ли е с DbConnection? - person Shimmy Weitzhandler; 26.12.2018
comment
@Shimmy: не, съжалявам - това е специфична функция за SQL Server, налична само на SqlConnection - person marc_s; 26.12.2018
comment
Благодаря за това! Сега използвам еквивалента на VB.NET AddHandler _con.InfoMessage, AddressOf InfoMessageHandler и съм доволен от това, което сега мога да получа от SET STATISTICS IO ON. - person Magnus Smith; 18.02.2019

Благодаря ви за отговора по-горе. Току-що направих малък експеримент и открих малък неочакван проблем (бъг?) при четене на съобщения (в този случай създадени от SET STATISTICS TIME ON) от резултат с множество записи. Както е посочено по-долу, човек трябва да извика NextResult дори след последния набор от резултати, за да получи последното съобщение. Това не е необходимо в случай на резултат от единичен набор от записи.

using System;
using System.Data.SqlClient;

namespace TimingTest
{
    class Program
    {

        static void Main(string[] args)
        {

            SqlConnection conn = new SqlConnection("some_conn_str");
            conn.Open();

            conn.InfoMessage += new SqlInfoMessageEventHandler(Message);

            SqlCommand cmd = new SqlCommand("some_sp", conn);
            cmd.CommandType = System.Data.CommandType.StoredProcedure;

            SqlDataReader rdr = cmd.ExecuteReader();

            while (rdr.Read()) { };

            rdr.NextResult();

            while (rdr.Read()) { };

            // this is needed to print the second message
            rdr.NextResult();

            rdr.Close();

            conn.Close();

        }

        static void Message(object sender, SqlInfoMessageEventArgs e)
        {
            Console.Out.WriteLine(e.Message);
        }

    }
}
person Jan Zich    schedule 19.04.2009
comment
Това би било чудесно като отговор на отделен въпрос, напр. Как да получа последното информационно съобщение след изпълнение на заявка, която връща множество набори от резултати? или нещо подобно. - person Kenny Evitt; 22.01.2012
comment
Като коментар към кода за всеки, който не знае, празните цикли while могат да бъдат написани и като: while (rdr.Read()) ; - person Samuel Slade; 28.03.2014

Въз основа на отговора на marc_s, създадох обвиващ клас

public class SqlInfoMessageWrapper
{
     public SqlInfoMessageWrapper(SqlConnection connection)
     {
            SqlConnection = connection;
            connection.InfoMessage += new SqlInfoMessageEventHandler(InfoMessageHandler);
      }
      public SqlConnection SqlConnection { get; set; }
      public string Message  { get; set; }

      void InfoMessageHandler(object sender, SqlInfoMessageEventArgs e)
      {
            Message = e.Message;
      }
 }

Пример за използване:

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

        var ret = SqlHelper2.ExecuteNonQuery(connection, CommandType.Text, command, null);
        messages+= $"{messageWrapper.Message} number of rows affected {ret} ";
    }
person Michael Freidgeim    schedule 30.11.2018