在Delphi异常中获取MS SQL Server异常用户消息



我正在使用Datasnap.DBClient从Delphi应用程序访问SQL Server数据库。

我有一个记录器,可以记录我的应用程序中的每一个异常,但我发现SQL异常消息真的很不友好。

示例:当我在Delphi中捕获SQL异常时,我得到的消息是:

EOleException:SQL状态:42S22,SQL错误代码:207

如果我在SQL事件探查器中打开跟踪,我会收到两条消息:

第一个异常与应用程序显示的消息相同:

异常:错误:207,严重性:16,状态:1

第二个是:

用户错误消息:列名"第1列"无效

是否有可能从我的Delphi应用程序中捕获的异常中获取此UserErrorMessage

我不确定你是在使用Ado还是DBExpress,但如果是DBExpress,你可能不会问这个问题(请参阅下面的更新)。

TAdoConnection有一个Errors对象(请参阅AdoInt.Pas中的定义)调查一下,我在服务器上使用了一个定义为的存储过程

create PROCEDURE [dbo].[spRaiseError](@AnError int)
AS
BEGIN
declare @Msg Char(20)
if @AnError > 0
begin
Select @Msg = 'MyError ' + convert(Char(8), @AnError)
RaisError(@Msg, 16, -1)
end
else
select 1
END

然后,在我的Delphi代码中,我有这样的东西:

uses [...] AdoInt, AdoDB, [...]
procedure TForm1.Button1Click(Sender: TObject);
var
S : String;
IErrors : Errors;
IError : Error;
ErrorCount : Integer;
i : Integer;
begin
S := 'exec spRaiseError ' + Edit1.Text;
AdoQuery1.SQL.Text := S;
try
AdoQuery1.Open;
except
IErrors := AdoConnection1.Errors;
ErrorCount := IErrors.Count;
for i := 0 to ErrorCount - 1 do begin
IError := IErrors.Item[i];
S := Format('error: %d, source: %s description: %s', [i, IError.Source, IError.Description]);
Memo1.Lines.Add(S);
end;
Caption := IntToStr(ErrorCount);
end;
end;

如果你尝试一下,你会发现Errors集合的内容是累积的,因此它应该捕获您想要的第二条消息。然而,我不完全确定当您说您使用"Datasnap-dbclient"时是什么意思:"dbclient"是声明TClientDataSet的单元,但您可能将其与ADO或DBExpress一起使用。我不确定DBXSqlServer驱动程序是否与AdoConnectionsErrors集合有任何对应项,您可以通过使用DBX组件来获得这些对应项。

更新使用上面的代码,如果我做了一个SELECT,故意引用一个不存在的列"aname",我会在Memo1:中得到这个

错误:0,源:用于SQL Server的Microsoft OLE DB提供程序描述:列名"aname"无效。

,但它不会报告您得到的错误207。

如果我在DBX项目中执行相同的SELECT,并在打开连接到SqlQuery的ClientDataSet时捕获异常,如下所示:

procedure TForm1.Button1Click(Sender: TObject);
var
S : String;
begin
S := 'select id, aname from atable';
ClientDataSet1.CommandText := S;
try
ClientDataSet1.Open;
except
Memo1.Lines.Add(Exception(ExceptObject).Message);
end;
end;

我得到这个

SQL状态:42000,SQL错误代码:8180无法准备语句。SQL状态:42S22,SQL错误代码:207列名"aname"无效。

这在某些方面更具信息性。同时,您的日志记录功能会记录以下内容:

Fecha: 2017-02-03 18:44:02
Sesion: {2E7176CB-56FD-41C4-BE67-7B9E1D3486B4}
Proyecto: dbxerrors.exe
Aplicación:    
Ruta: D:aaad7Ado
Usuario: ???
Error: SQL State: 42000, SQL Error Code: 8180
Statement(s) could not be prepared.
SQL State: 42S22, SQL Error Code: 207
Invalid column name 'aname'.
Exception EDatabaseError: SQL State: 42000, SQL Error Code: 8180
Statement(s) could not be prepared.
SQL State: 42S22, SQL Error Code: 207
Invalid column name 'aname'.
Exception 
UnitName : 
Procedure : 
Line : 0
BinaryFileName : 

Fecha: 2017-02-03 18:44:02
Sesion: {2E7176CB-56FD-41C4-BE67-7B9E1D3486B4}
Proyecto: dbxerrors.exe
Aplicación:    
Ruta: D:aaad7Ado
Usuario: ???
Error: SQL State: 42000, SQL Error Code: 8180
Statement(s) could not be prepared.
SQL State: 42S22, SQL Error Code: 207
Invalid column name 'aname'
Exception EOleException: SQL State: 42000, SQL Error Code: 8180
Statement(s) could not be prepared.
SQL State: 42S22, SQL Error Code: 207
Invalid column name 'aname'
Exception 
UnitName : 
Procedure : 
Line : 0
BinaryFileName : 

如果有帮助的话,这是我的测试项目的DFM 的部分摘录

object SQLConnection1: TSQLConnection
ConnectionName = 'MSSQLConnection'
DriverName = 'MSSQL'
GetDriverFunc = 'getSQLDriverMSSQL'
LibraryName = 'dbexpmss.dll'
LoginPrompt = False
Params.Strings = (
'DriverName=MSSQL'
'HostName=MAT410ss2014'
'DataBase=MATest'
'User_Name=sa'
'Password=sa'
'BlobSize=-1'
'ErrorResourceFile='
'LocaleCode=0000'
'MSSQL TransIsolation=ReadCommited'
'OS Authentication=False')
VendorLib = 'oledb'
Left = 40
Top = 32
end
object SQLQuery1: TSQLQuery
MaxBlobSize = -1
Params = <>
SQLConnection = SQLConnection1
Left = 88
Top = 32
end
object DataSetProvider1: TDataSetProvider
DataSet = SQLQuery1
Options = [poAllowCommandText]
Left = 136
Top = 32
end
object ClientDataSet1: TClientDataSet
Aggregates = <>
Params = <>
ProviderName = 'DataSetProvider1'
Left = 184
Top = 32
end

正如你所看到的,它是非常简约的。Delphi版本是在Win10 64位上的D7,服务器是Sql server 2014。

最新更新