【问题标题】:Getting MS SQL Server Exception User Message in Delphi exception在 Delphi 异常中获取 MS SQL Server 异常用户消息
【发布时间】:2017-02-02 14:18:24
【问题描述】:

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

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

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

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

如果我在 SQL Profiler 中打开跟踪,我会收到两条消息:

第一个,Exception 与应用显示的消息相同:

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

第二个,是:

用户错误消息:列名“Column1”无效

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

【问题讨论】:

    标签: sql-server delphi exception


    【解决方案1】:

    我不确定您使用的是 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 一起使用。我不确定 DBX Sql Server 驱动程序是否有任何对应的 AdoConnections Errors 集合,您可以通过使用 DBX 组件获得。

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

    错误:0,来源:Microsoft OLE DB Provider for SQL Server 描述:列名“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:\aaad7\Ado\
    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:\aaad7\Ado\
    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=MAT410\ss2014'
          '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。

    【讨论】:

    • 谢谢@MartynA。我正在使用 DBExpress。你是怎么得到你答案最后的描述的?
    • 我实际上是在使用 JCLDebugger 获得异常,除了捕获它之外我没有尝试。这个想法是在一个文本文件中记录每个 SQL 错误。
    • @Andres:“你是如何在你的答案最后得到那个描述的”查看我刚刚添加到我的答案中的代码。
    • 好吧@MartynA,这就是我正在做的事情,但我只是收到以下错误:SQL 状态:42S22,SQL 错误代码:207。我缺少“无效的列名”部分。我是否需要在 Delphi 或 SQL Server 中设置一些配置才能接收该消息?
    • @Andres:抱歉,我的 DBX 测试项目中只有代码,但我添加了 DFM 的文本摘录,以防它帮助您发现与您的不同之处。
    猜你喜欢
    • 1970-01-01
    • 2014-06-14
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 2011-06-08
    相关资源
    最近更新 更多