ASP.NET SQL Server存储过程返回消息

时间:2017-03-01 21:26:21

标签: c# asp.net sql-server stored-procedures

我有一个不需要任何参数的存储过程,并返回值0和消息:

(94 row(s) affected)

(1 row(s) affected)

我的问题是如何获取消息:

(94 row(s) affected)

(1 row(s) affected)

这是我调用存储过程的.NET方法:

public List<MessageClass> ChequesToUpdate()
{
    message = new List<MessageClass>();

    MessageClass item = new MessageClass();

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

            using (SqlCommand command = new SqlCommand("MyStoredProcedure", connection))
            {
                command.CommandType = CommandType.StoredProcedure;

                command.ExecuteNonQuery();

                item.message = "message";
            }
        }
    }
    catch (Exception e)
    {
        item.message = e.Message;
    }
    finally
    {
        connection.Close();
    }

    message.Add(item);

    return message;
}

我希望将信息放在item.message中,我该如何做到这一点?

6 个答案:

答案 0 :(得分:3)

在您的存储过程中,您可以查询@@ROWCOUNT,它会为您提供受影响的记录。现在,您可以使用SETSELECT语句(例如

)将其存储到变量中
SET MyRecordCount = @@RowCount

SELECT MyRecordCount = @@RowCount

或者,如果您在一个程序中有多个操作,则需要跟踪您可以创建多个变量并多次调用SETSELECT或使用TABLE变量,例如

DECLARE @recordCount table (Records int not null)

--RUN PROCEDURE CODE

INSERT INTO @recordCount VALUES (@@ROWCOUNT)

--RUN MORE PROCEDURECT CODE

INSERT INTO @recordCount VALUES (@@ROWCOUNT)

--RETURN THE Row Count
SELECT Records FROM @recordCount

这会将@@ROWCOUNT的值插入表变量@recordCount

接下来要获取此信息,您需要从@recordCount表中选择最后一行。

最后在您的代码中使用数据读取器而不是ExecuteNonQuery()方法。

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

    using (SqlCommand command = new SqlCommand("MyStoredProcedure", connection))
    {
        command.CommandType = CommandType.StoredProcedure;

        using (var reader = command.ExecuteReader())
        {
            while (reader.Read())
            {
                item.message = reader.GetString(0);
            }
            reader.Close();
        }
    }

}

现在消息实际上是受影响的行的整数而不是术语(98) row affected但是如果你真的想要那个确切的消息可以按照你的意愿格式化字符串。

item.message = string.Format("({0}) rows affected", reader.GetInt32(0))

答案 1 :(得分:3)

ExecuteNonQuery返回受影响行的总数。因此,如果您只想要行的总数,那么您只需使用以下语句即可获得它:

var x = command.ExecuteNonQuery();

否则,您必须在存储过程中使用用户定义RAISERROR消息并从C#connection.InfoMessage事件中捕获它。我已经设置了测试环境并对其进行了测试。我创建了一个表并插入了一些数据来检查我的SQL&amp; C#代码。请查看下面的SQL&amp; C#代码。

SQL:

Create Table psl_table
(
    [values] NVarChar(MAX)
)

Insert Into psl_table Values('a')
Insert Into psl_table Values('a')
Insert Into psl_table Values('a')
Insert Into psl_table Values('b')
Insert Into psl_table Values('b')
Insert Into psl_table Values('b')
Insert Into psl_table Values('b')
Insert Into psl_table Values('b')
Insert Into psl_table Values('b')
Insert Into psl_table Values('b')

Create Proc MyStoredProcedure
    As
Begin
    -- Declare a variable for Message
    Declare @Msg NVarChar(MAX)

    -- 1st SQL Statement
    Update psl_table Set [Values]='a' Where [Values]!='a'

    -- Generate the message and print that can get from C#
    Set @Msg = '(' + Convert(NVarChar,@@RowCount) + ' row(s) affected)'
    RAISERROR( @Msg, 0, 1 ) WITH NOWAIT

    -- 2nd SQL Statement
    Update psl_table Set [Values]='a'

    -- Generate the message and print that can get from C#
    Set @Msg = '(' + Convert(NVarChar,@@RowCount) + ' row(s) affected)'
    RAISERROR( @Msg, 0, 1 ) WITH NOWAIT
End

在这个SQL中,我已经声明了一个变量 @Msg 来存储消息和内置函数 RAISERROR 来抛出消息。

C#CODE:

public List<MessageClass> ChequesToUpdate()
{
    message = new List<MessageClass>();

    MessageClass item = new MessageClass();

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

            connection.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs e)
            {
                item.message = e.Message;
            };

            using (SqlCommand command = new SqlCommand("MyStoredProcedure", connection))
            {
                command.CommandType = CommandType.StoredProcedure;

                command.ExecuteNonQuery();
            }
        }
    }
    catch (Exception e)
    {
        item.message = e.Message;
    }
    finally
    {
        connection.Close();
    }

    message.Add(item);

    return message;
}

我已经修改了所需输出的代码。我使用 connection.InfoMessage 事件来捕获从SQL抛出的消息。

出于测试目的,我在Console中打印输出。

输出:

Output

答案 2 :(得分:0)

存储过程中语句的每一端,在表中插入@@rowcount。然后使用数据集将其提取回Method。

答案 3 :(得分:0)

默认情况下,您无法在C#中获取受行影响的消息。相反,您需要将您的过程修改为PRINT/RAISERROR消息,这样您就可以使用@Julian提到的SqlConnection.InfoMessage在C#中访问它们。

Return rows affected from a Stored Procedure on each INSERT to display in ASP.NET page - Stackoverflow

答案 4 :(得分:0)

我会从程序返回@@ rowcount,在.net代码中我会读取该值。

在您的程序中添加return(@@ rowcount),如下所示

create procedure testprocedure
as
begin
    update test1 set id =100
    return(@@rowcount)
end

您的.net代码在参数方向

下面显示如下
    SqlConnection conn;
        using(conn = new SqlConnection(@"Data Source=;Initial Catalog=;User ID = sa;Password="))
        {
            conn.Open();

            using (SqlCommand command = new SqlCommand("testprocedure", conn))
            {
                command.CommandType = CommandType.StoredProcedure;
                SqlParameter retValue = command.Parameters.Add("return", SqlDbType.Int);
                retValue.Direction = ParameterDirection.ReturnValue;
                command.ExecuteNonQuery();
                Console.WriteLine("no of records affected " + retValue.Value);
                Console.ReadLine();
            }
        } 

答案 5 :(得分:0)

您无法捕获这些特定消息(即(94 row(s) affected)),因为它们不是由SQL Server发送的;它们由客户端程序发送,SQLCMD或SSMS。但是,是的,您可以捕获行计数,而无需向存储过程添加RAISERRORPRINT语句。此外,您(或许多其他人阅读此问题)甚至可能无法更新存储过程以注入输出的额外PRINT / RAISERROR / SELECT语句行数。

但首先,关于其他一些建议的两个警告:

  1. 您可能无法使用ExecuteNonQuery的返回值,因为它不会返回非DML语句的值,包括SELECT语句。它只返回INSERTUPDATEDELETE语句中的值,如SqlCommand.ExecuteNonQuery所述:

      

    对于UPDATE,INSERT和DELETE语句,返回值是受命令影响的行数。 ...对于所有其他类型的语句,返回值为-1。

    问题并未说明正在执行哪些类型的查询,因此您可能只使用这些DML语句。但是,每个人都应该知道这个返回值反映了什么(而不是)。

  2. 您可能不希望通过InfoMessage处理程序捕获打印消息,因为这需要解析以确保捕获的消息不是其他消息,例如警告或其他信息。

  3. 话虽这么说,你想设置一个SqlCommand.StatementCompleted事件处理程序,因为它传递了每个语句受影响的行(RecordCountint)。

    internal static void StatementCompletedHandler(object Sender,
    StatementCompletedEventArgs EventInfo)
    {
        // do something with EventInfo.RecordCount
    
        return;
    }
    

    然后将其附加到SqlCommand对象:

    _Command.StatementCompleted += StatementCompletedHandler;
    

    如果在ASP.NET中工作限制了将返回值存储在静态变量中的能力(因为它是共享的并且可能不是线程安全的),那么您可以将处理程序内联定义为匿名委托,在这种情况下它能够访问在ChequesToUpdate方法中声明的实例变量。