从LINQ ExecuteMethodCall中提取SQL“print”消息

时间:2013-09-20 10:50:05

标签: c# sql sql-server linq stored-procedures

我通过LINQ以一种相当简单的方式调用存储过程:

    [Function(Name = "dbo.add_second_override")]
    public int AddSecondOverride(
        [Parameter(DbType = "numeric(10)")] decimal account_id,
        [Parameter(DbType = "numeric(10)")] decimal security_id,
        [Parameter(DbType = "varchar(255)")] string reason,
        [Parameter(DbType = "numeric(10)")] decimal? order_id,
        [Parameter(DbType = "numeric(10)")] decimal current_user)
    {
        IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), new object[] { account_id, security_id, reason, order_id, current_user });

        if ((int)result.ReturnValue != 0)
        {
            string errorDescription = Sysmessages.FirstOrDefault(x => x.Error == (int)result.ReturnValue).Description;
            throw new Exception(errorDescription);
        }

        return (int)result.ReturnValue;
    }

这很好用,但是如果存储过程中有一个SQL print语句,我该如何提取这些信息呢? E.g。

create procedure dbo.add_second_override
(   
    @account_id numeric(10), 
    @security_id numeric(10), 
    @reason varchar(255) = null output,
    @order_id numeric(10) = null,
    @current_user numeric(10)               
) 
as
begin
    /* Do some other stuff */
    print 'This is a SQL message'
    return 0
end

以前有一种方法可以使用SQLClient检索此消息,但我找不到与LINQ相关的任何内容。

请注意,我无法在存储过程中抛出异常,而不是使用“print”。它必须以某种方式获取打印报表。

2 个答案:

答案 0 :(得分:4)

我没有找到任何具体的Linq。但从这个问题排队

Capture Stored Procedure print output in .NET (Different model!)

如果你可以挂钩到SqlConnection,你可以对InfoMessage事件作出反应。

如果您正在使用Entity Framework和DbContext - 您可以这样做。

SqlConnection conn = (SqlConnection)context.Database.Connection;
conn.Open();
conn.InfoMessage += (s, e) => Console.WriteLine(e.Message);

正如我所说,我意识到这不是Linq特定的方法 - 但至少你可以通过这样的方式实现你的最终目标。

答案 1 :(得分:0)

我花了一些时间,以防万一有人碰到它。

我的存储过程执行约30分钟。我想在执行期间将PRINT消息传递给用户。问题是MS SQL Servcer具有用于输出消息的缓冲区,要刷新此缓冲区,您需要使用RAISEERROR('',0,1)-0,1在这里很重要。 TRY / CATCH正在处理高于10的消息。

我还必须将FireInfoMessageEventOnUserErrors设置为true:

  

将FireInfoMessageEventOnUserErrors设置为true时,以前被视为异常的错误现在将作为InfoMessage事件处理。所有事件均立即触发,并由事件处理程序处理。如果将FireInfoMessageEventOnUserErrors设置为false,则在该过程结束时处理InfoMessage事件。

            var ctx = new EFContext();
            var sqlConnection = (SqlConnection)_ctx.Database.Connection;

            sqlConnection.Open();
            sqlConnection.InfoMessage += (s, a) =>
            {
                Clients.All.notifyAll("MSG from server:" + a.Message);
            };
            sqlConnection.FireInfoMessageEventOnUserErrors = true;//this line will fire InfoMessage on every print or RAISERROR line
            var b = ctx.Database.ExecuteSqlCommand(@"
DECLARE @startTime datetime2(0) = GETDATE();

WHILE (GETDATE() < DATEADD(SECOND, 10, @startTime))
BEGIN

    PRINT 'HELLO FROM SP:'+CONVERT(nvarchar(max), DATEDIFF(SECOND, @startTime, GETDATE()))

    RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT -- this will flush MS SQL buffer and you can get messages immediately when they occurs
    WAITFOR DELAY '00:00:03';
END");


            Clients.All.notifyAll("Execution finished with result:" + b);