【问题标题】:Extract SQL 'print' messages from LINQ ExecuteMethodCall从 LINQ ExecuteMethodCall 中提取 SQL“打印”消息
【发布时间】:2013-09-25 17:34:39
【问题描述】:

我通过 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 打印语句,我该如何提取这些信息? 例如

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 相关的任何内容。

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

【问题讨论】:

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


    【解决方案1】:

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

    我的存储过程执行约 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);
    

    【讨论】:

      【解决方案2】:

      我没有找到任何特定于 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 的方法 - 但至少您可以通过这样的方式实现最终目标。

      【讨论】:

      • 谢谢肖恩。我实际上使用的是 DBML DataContext 而不是实体框架,但我调整了您的解决方案,它对我有用。我没有意识到您可以简单地将其转换为 SqlConnection。谢谢!
      猜你喜欢
      • 2010-10-04
      • 1970-01-01
      • 2016-12-04
      • 2014-12-27
      • 1970-01-01
      • 1970-01-01
      • 2011-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多