从 LINQ ExecuteMethodCall 中提取 SQL “打印”消息
本文关键字:打印 消息 SQL 提取 LINQ ExecuteMethodCall | 更新日期: 2023-09-27 18:32:03
我以一种相当简单的方式通过 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 内容。
请注意,我无法在存储过程中引发异常,而不是使用"print"。它必须以某种方式拾取打印语句。
我没有找到任何特定于Linq的内容。 但是从这个问题中排队
在 .NET 中捕获存储过程打印输出(不同的模型!
如果你可以挂接到SqlConnection,你就可以对InfoMessage事件做出反应。
如果您使用的是实体框架和 DbContext - 您可以执行以下操作。
SqlConnection conn = (SqlConnection)context.Database.Connection;
conn.Open();
conn.InfoMessage += (s, e) => Console.WriteLine(e.Message);
正如我所说,我意识到这不是 Linq 特有的方法 - 但至少你可以通过这样的东西实现你的最终目标。
我花了一些时间,以防万一有人遇到它。
我有执行~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);
我使用ToQueryString()来测试我的Linq脚本。
var query = appDbContext.SomeTable.Where(x=>x.someFeild==anyData);
System.Diagnostics.Debug.WriteLine(query.ToQueryString());