简体   繁体   English

如何从C#中的SQL存储过程中检索结果集和PRINT消息?

[英]How can retrieve both a result set and a PRINT message from a SQL stored procedure in C#?

I have a stored procedure that can return both a PRINT message and regular query results from a SELECT statement. 我有一个存储过程,可以从SELECT语句返回PRINT消息和常规查询结果。 Using the elegant solution provided in this thread , I can easily capture my PRINT message when invoking SqlCommand.ExecuteNonQuery() in my C# code. 使用此线程中提供的优雅解决方案,我可以在我的C#代码中调用SqlCommand.ExecuteNonQuery()时轻松捕获我的PRINT消息。 The problem is, I also want to return my result set. 问题是,我也想返回我的结果集。

When I use a SqlDataReader to get back the query results from my stored proc using SqlCommand.ExecuteReader , the event handler that captures my PRINT message never fires like it does when I use SqlCommand.ExecuteNonquery . 当我使用SqlDataReader使用SqlCommand.ExecuteReader从我的存储过程中获取查询结果时,捕获我的PRINT消息的事件处理程序永远不会像我使用SqlCommand.ExecuteNonquery时那样触发。

It's beginning to seem like I can only have one or the other. 它似乎开始似乎只能有一个或另一个。 Is there a way for me to capture both my PRINT message and my query results? 有没有办法捕获我的PRINT消息查询结果?

Here's a snippet of my SQL stored procedure: 这是我的SQL存储过程的片段:

IF EXISTS
(
    SELECT MFG_PART_NUMBER, COUNT(*) AS RecordCount
    FROM [PartsManagement].[ManufacturerCatalogPart] 
    WHERE CatalogID = @CatalogID
    GROUP BY MFG_PART_NUMBER
    HAVING COUNT(*) > 1
)
    BEGIN

    SELECT MFG_PART_NUMBER, COUNT(*) AS RecordCount
    FROM [PartsManagement].[ManufacturerCatalogPart] 
    WHERE CatalogID = @CatalogID
    GROUP BY MFG_PART_NUMBER
    HAVING COUNT(*) > 1;

    PRINT 'The update was not executed because duplicate MFG_PART_NUMBERs were found in the catalog. Delete the duplicates and try again.';

END;

And here's a snippet from my code: 这是我代码中的一个片段:

//field
private string sqlPrintMessage = "";

//event handler for sql PRINT message
void myConnection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
    sqlPrintMessage = e.Message;
}

public void SomeMethod()
{
    using (SqlConnection sqlcon = new SqlConnection(ConnectionManager.GetConnectionString()))
    {
        sqlcon.InfoMessage += new SqlInfoMessageEventHandler(myConnection_InfoMessage);

        SqlCommand sqlcmd = new SqlCommand("[ManufacturerCatalogUpdate].[CheckCatalogForDuplicates]", sqlcon);
        sqlcmd.CommandType = CommandType.StoredProcedure;
        sqlcmd.Parameters.AddWithValue("@CatalogID", catalogID);
        sqlcon.Open();
        //SqlDataReader reader = sqlcmd.ExecuteReader();
        sqlcmd.ExecuteNonQuery();
        if (sqlPrintMessage == "") //then proceed with update
        {
            //do some logic
        }
        else
        {
            //System.Diagnostics.Debug.WriteLine(sqlPrintMessage);
            //List<DuplicatePartCount> duplicateParts = new List<DuplicatePartCount>();
            //while (reader.Read())
            //{
            //    DuplicatePartCount record = new DuplicatePartCount();
            //    record.MFG_PART_NUMBER = reader.GetString(0);
            //    record.count = reader.GetInt32(1);
            //    duplicateParts.Add(record);
            //}
        }
    }
}

There are two way to do it based on selection of sql execution. 基于sql执行的选择,有两种方法可以做到这一点。

1) If you are using ExecuteNonQuery than use OUT param in sproc like below. 1)如果你使用的是ExecuteNonQuery不是像下面那样在sproc中使用OUT param。

CREATE PROCEDURE GetEmployee
   @employeeID INT,
   @Message VarChar(100) OUTPUT
AS
BEGIN
   -- Here is your result set from select statement
   SELECT Emp_Name From Employee Where EmpId = @employeeID 

   -- Here is your message
   SELECT @Message = 'Your Message!'
END

Now to get it in your code pass @Message parameter with OUT like below. 现在要在你的代码中使用OUT传递@Message参数,如下所示。

//Add the output parameter to the command object
SqlParameter outPutParameter = new SqlParameter();
outPutParameter.ParameterName = “@Message”;
outPutParameter.SqlDbType = System.Data.SqlDbType.Varchar;
outPutParameter.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.Add(outPutParameter);

cmd.ExecuteNonQuery();

//Retrieve the value of the output parameter
string Message = outPutParameter.Value.ToString();

// You can get remaining result set as always

2) If you are using Reader than.... 2)如果你使用的是阅读器而不是....

Set the message and use Select statement instead of print.Like below' 设置消息并使用Select语句而不是print.Like在'下面'

 SELECT Emp_Name From Employee Where EmpId = @employeeID 
  -- It should be set previously
  SELECT @Message

To get in your code just Use 要获取代码,请使用

using (SqlDataReader reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                //Your result set or message
            }

            if(reader.NextResult())
            {
               while (reader.Read())
              {
                 //Your result set or message
              }
            }
        }

So, I think we first need to rethink the operation here. 所以,我认为我们首先需要重新考虑这里的操作。 You want to do a duplicate as a test to determine if the app code should proceed or not. 您希望将副本作为测试来确定应用程序代码是否应该继续。 The proc returns a result set and then prints a message if there are dupes, else returns neither. proc返回一个结果集,如果有dupes则打印一条消息,否则返回。 And you are inferring that there will be a result set based on the existence of a captured message. 并且您推断基于捕获的消息的存在将存在结果集。 That type of indirect test is less than ideal and unnecessary. 这种类型的间接测试不太理想和不必要。

A direct and simpler method is available to test for the existence of a result set. 可以使用直接且更简单的方法来测试结果集的存在。 Forget the message (especially since you aren't even using it) and instead just check the data reader: 忘记消息(特别是因为你甚至没有使用它)而只是检查数据阅读器:

    if (reader.HasRows())
    {
        //System.Diagnostics.Debug.WriteLine(sqlPrintMessage);
        //List<DuplicatePartCount> duplicateParts = new List<DuplicatePartCount>();
        //while (reader.Read())
        //{
        //    DuplicatePartCount record = new DuplicatePartCount();
        //    record.MFG_PART_NUMBER = reader.GetString(0);
        //    record.count = reader.GetInt32(1);
        //    duplicateParts.Add(record);
        //}
    }
    else
    {
        //do some logic
    }

If you are still just curious about the PRINT message getting trapped, do these two tests: 如果您仍然只是对PRINT消息陷入困境感到好奇,请执行以下两项测试:

  1. First, add a second System.Diagnostics.Debug.WriteLine(sqlPrintMessage); 首先,添加第二个System.Diagnostics.Debug.WriteLine(sqlPrintMessage); AFTER the while loop, and re-run the test while循环之后,重新运行测试
  2. Second, without removing the 2nd debug line from #1, add a second PRINT command between the BEGIN and SELECT , with different text so that you can distinguish between them if necessary, and re-run the test 其次,在不从#1中删除第二个调试行的情况下,在BEGINSELECT之间添加第二个PRINT命令,使用不同的文本,以便在必要时可以区分它们,并重新运行测试

Also, the following "Remarks" from the MSDN page for the SqlConnection.FireInfoMessageEventOnUserErrors property might shed some light on this behavior: 此外,来自MSDN页面的SqlConnection.FireInfoMessageEventOnUserErrors属性的以下“备注”可能会对此行为有所了解:

When you set FireInfoMessageEventOnUserErrors to true , errors that were previously treated as exceptions are now handled as InfoMessage events. 将FireInfoMessageEventOnUserErrors设置为true时 ,先前作为异常处理的错误现在将作为InfoMessage事件处理。 All events fire immediately and are handled by the event handler. 所有事件立即触发并由事件处理程序处理。 If is FireInfoMessageEventOnUserErrors is set to false , then InfoMessage events are handled at the end of the procedure. 如果FireInfoMessageEventOnUserErrors设置为false ,则在过程结束时处理InfoMessage事件。

So, if you wanted / needed the messages as they happen , then you can set FireInfoMessageEventOnUserErrors to true , but that might alter the behavior of catching exceptions that might be more undesirable than getting the messages immediately. 所以,如果你想/需要的消息,因为它们发生的 ,那么你可以设置FireInfoMessageEventOnUserErrorstrue ,但可能会改变捕获异常,可能是不是马上得到消息更不可取的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从使用EntityFramework构建的C#项目中的ComplexType Sql Server存储过程中检索数据 - How to retrieve data from a ComplexType Sql Server stored procedure inside C# project built with EntityFramework 如何从C#中的存储过程中检索HTML文本 - How to retrieve html text from stored procedure in C# 如何从存储过程中获取SQL字符串结果并将其保存在C#Windows应用程序字符串变量中 - How to get SQL String Result from Stored Procedure and save it in C# Windows Application string variable 如何从C#中的SQL Server存储过程获取返回的结果 - How to get the result returned back from a SQL Server stored procedure in C# 如何获得C#中存储过程的结果? - How can I get the result of a stored procedure in C#? 如何使用C#检索存储过程? - How to retrieve a stored procedure using c#? 如何从存储过程中获取错误消息并在 c# 上显示? - How to Get Error message from stored procedure into display on c#? 如何从从 SQL Server 存储过程获取 JSON 结果的 C# Web API 返回 JSON 结果? - How to return JSON result from C# Web API that gets JSON result from SQL Server Stored Procedure? 如何从C#中的存储过程中获取设置值 - How To Get Set Value From Stored procedure in C# 如何将数据表从 C# 传递到 SQL 服务器存储过程 - How to pass datatable from C# to SQL Server stored procedure
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM