【问题标题】:View output of 'print' statements using ADOConnection in Delphi在 Delphi 中使用 ADOConnection 查看“打印”语句的输出
【发布时间】:2010-09-20 05:58:06
【问题描述】:

我的一些 MS SQL 存储过程使用“打印”命令生成消息。在我的 Delphi 2007 应用程序中,它使用 TADOConnection 连接到 MS SQL,我如何查看这些“打印”命令的输出?

关键要求: 1) 我不能多次运行查询;它可能正在更新东西。 2) 即使返回数据集,我也需要查看“打印”结果。

【问题讨论】:

    标签: sql-server delphi stored-procedures ado


    【解决方案1】:

    这是一个有趣的事件...
    来自 ADOConnection 的 OnInfoMessage 事件有效,但魔鬼在细节中!

    要点:
    使用 CursorLocation = clUseServer 而不是默认的 clUseClient。
    在您的 ADOStoredProc 中使用 Open 而不是 ExecProc。
    使用当前记录中的 NextRecordset 获取以下内容,但请务必检查您是否打开了一个。
    在存储过程中使用 SET NOCOUNT = ON。

    SQL 端:您的存储过程

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[FG_TEST]') AND type in (N'P', N'PC'))
      DROP PROCEDURE [dbo].[FG_TEST]
    GO
    -- =============================================
    -- Author:      François
    -- Description: test multi ADO with info
    -- =============================================
    CREATE PROCEDURE FG_TEST
    AS
    BEGIN
        -- SET NOCOUNT ON absolutely NEEDED
        SET NOCOUNT ON;
    
        PRINT '*** start ***'
    
        SELECT 'one' as Set1Field1
    
        PRINT '*** done once ***'
    
        SELECT 'two' as Set2Field2
    
        PRINT '*** done again ***'
    
        SELECT 'three' as Set3Field3
    
        PRINT '***finish ***'
    END
    GO
    

    德尔福方面:
    创建一个新的 VCL 表单应用程序。
    在您的表单中放置一个备忘录和一个按钮。

    复制以下文本,更改目录和数据源并将其粘贴到您的表单上

    object ADOConnection1: TADOConnection
      ConnectionString = 
        'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In' +
        'fo=False;Initial Catalog=xxxYOURxxxDBxxx;Data Source=xxxYOURxxxSERVERxxx'
      CursorLocation = clUseServer
      LoginPrompt = False
      Provider = 'SQLOLEDB.1'
      OnInfoMessage = ADOConnection1InfoMessage
      Left = 24
      Top = 216
    end
    object ADOStoredProc1: TADOStoredProc
      Connection = ADOConnection1
      CursorLocation = clUseServer
      ProcedureName = 'FG_TEST;1'
      Parameters = <>
      Left = 24
      Top = 264
    end
    

    在ADOConnection的OnInfoMessage中放

    Memo1.Lines.Add(Error.Description);
    

    对于 ButtonClick,粘贴此代码

    procedure TForm1.Button1Click(Sender: TObject);
    const
      adStateOpen = $00000001; // or defined in ADOInt
    var
      I: Integer;
      ARecordSet: _Recordset;
    begin
      Memo1.Lines.Add('==========================');
    
      ADOStoredProc1.Open; // not ExecProc !!!!!
    
      ARecordSet := ADOStoredProc1.Recordset;
      while Assigned(ARecordSet) do
      begin
        // do whatever with current RecordSet
        while not ADOStoredProc1.Eof do
        begin
          Memo1.Lines.Add(ADOStoredProc1.Fields[0].FieldName + ': ' + ADOStoredProc1.Fields[0].Value);
          ADOStoredProc1.Next;
        end;
        // switch to subsequent RecordSet if any
        ARecordSet := ADOStoredProc1.NextRecordset(I);
        if Assigned(ARecordSet) and ((ARecordSet.State and adStateOpen) <> 0) then
          ADOStoredProc1.Recordset := ARecordSet
        else
          Break;
      end;
    
      ADOStoredProc1.Close;
    end;
    

    【讨论】:

    • 这绝对让我走上了正确的道路:为了灵活性,我使用了 TADOCommand 而不是 TADOStoredProc,它仍然有效。 SET NOCOUNT ON 似乎也是可选的:如果您没有它,它只会打印额外的消息。并且 clUseServer 使记录集在 TDBGrid 中不可用:(
    • 上面的 OninfoMessage 代码只显示了第一条 PRINT 消息。要将它们全部打印出来(例如,如果 SELECT 语句之间有超过 1 个 PRINT 语句),请执行以下操作: var i: integer; begin for i := 0 to AdoConnection1.Errors.Count - 1 do begin // cxMemo1.Lines.Add(Error.Description); cxMemo1.Lines.Add(ADOConnection1.Errors.Item[i].Description);结尾;结束;
    【解决方案2】:

    .net 的连接类中有一个名为 InfoMessage 的事件。在此事件的处理程序中,您可以从事件 args 中检索 InfoMessage(打印语句)。

    我相信 Delphi 有一个名为“OnInfoMessage”的类似事件可以帮助您。

    【讨论】:

    • 这很接近了!如果我设置 command.ExecuteOptions = [eoExecuteNoRecords],它会起作用。但这阻止了我获取任何数据集。嗯……
    【解决方案3】:

    我认为这是不可能的。 您可以使用临时表转储打印语句并将其与结果一起返回。

    【讨论】:

      【解决方案4】:

      对 Francois 的代码(使用 DXE2 测试)进行了一些增强,以适应多个打印语句和来自可变数量选择的结果。变化很微妙。

      procedure TForm1.ADOConnection1InfoMessage(Connection: TADOConnection;
        const Error: Error; var EventStatus: TEventStatus);
      var
        i: integer;
      begin
        // show ALL print statements
        for i := 0 to AdoConnection1.Errors.Count - 1 do
        begin
          // was: cxMemo1.Lines.Add(Error.Description);
          cxMemo1.Lines.Add(
            ADOConnection1.Errors.Item[i].Description);
        end;
      end;
      
      procedure TForm1.cxButton1Click(Sender: TObject);
      const
        adStateOpen = $00000001; // or uses ADOInt
      var
        records: Integer;
        ARecordSet: _RecordSet;
      begin
        cxMemo1.Lines.Add('==========================');
      
        ADOStoredProc1.Open;
      
        try
          ARecordSet := ADOStoredProc1.RecordSet; // initial fetch
          while Assigned(ARecordSet) do
          begin
            // assign the recordset to a DataSets recordset to traverse
            AdoDataSet1.Recordset := ARecordSet;
            // do whatever with current ARecordSet
            while not ADODataSet1.eof do
            begin
              cxMemo1.Lines.Add(ADODataSet1.Fields[0].FieldName + 
                ': ' + ADODataSet1.Fields[0].Value);
              AdoDataSet1.Next;
            end;
            // fetch next recordset if there is one
            ARecordSet := ADOStoredProc1.NextRecordSet(records);
            if Assigned(ARecordSet) and ((ARecordSet.State and adStateOpen) <> 0) then
              ADOStoredProc1.Recordset := ARecordSet
            else
              Break;
          end;
        finally
          ADOStoredProc1.Close;
        end;
      
      end;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-23
        • 2021-09-03
        相关资源
        最近更新 更多