捕获 TClientDataSet.CommandText 中的错误

Posted

技术标签:

【中文标题】捕获 TClientDataSet.CommandText 中的错误【英文标题】:Trapping errors in TClientDataSet.CommandText 【发布时间】:2010-05-13 02:52:45 【问题描述】:

我有一个 TClientDataSet 连接到一个 TDataSetProvider,而 TDataSetProvider 又连接到一个 TAdsQuery。我设置了 SQL 命令,然后像这样打开 ClientDataset:

try
  CDS.CommandText := 'SELECT * FROM tablename WHERE fieldname = 1';
  CDS.Open
except
  // trap exception here - this never gets executed!
end;

但是,如果 CommandText 中的 SQL 语句失败(语法错误或其他),我会在 Advantage 代码中得到一个异常,但它永远不会在我自己的异常处理代码中被捕获。

我有什么方法可以捕获此错误并将其很好地报告给用户。或者有没有办法在执行 SQL 查询之前验证它的语法?

我正在使用 Delphi Pro 2009 和 Advantage Local Server 9。

【问题讨论】:

【参考方案1】:

Advantage 包括一个EADSDatabaseError,它将提供有关引发的异常的更多信息。

try
  CDS.CommandText := 'SELECT * FROM tablename WHERE fieldname = 1';
  CDS.Open
except
on E: EDatabaseError do
begin
  if ( E is EADSDatabaseError ) then
  begin
    ErrorString := (E as EADSDatabaseError).SQLErrorCode + E.Message;
    application.messagebox ( pchar(ErrorString), 'Advantage Database Error', 0 )
  end
  else
    application.messagebox (pchar(E.message), 'Native Database Error', 0 );
  end;
end;

您可以使用 TAdsQuery 组件的VerifySQL 方法在执行 SQL 语句之前检查它的语法。如果 SQL 语法不正确,这将引发 EADSDatabaseError 异常。

【讨论】:

酷,我从来不知道 VerifySQL 方法。我开始怀疑我的代码中存在一些其他问题,这些问题正在破坏异常,但是能够在运行之前验证 SQL 总比事后捕获异常要好。【参考方案2】:

当您从 IDE 中运行它时,或者当您直接从可执行文件运行时,您是否获得了异常代码(不是您想要的捕获的异常)?我问的原因是IDE会首先报告错误/异常,如果你不继续,你将永远看不到实际的异常陷阱。

可以针对某些错误类型关闭 IDE 捕获,尽管我一般不喜欢这样做。您可以通过在 Delphi IDE 之外自行运行应用程序来检查这是否是问题所在。

此外,您最初编写的代码应该防止所有错误浮出水面,这可能不是您想要的。同样的道理,如果你想让它看起来更好,你可以显示消息,如下所示,然后处理它。

try 
  CDS.CommandText := 'SELECT * FROM tablename WHERE fieldname = 1'; 
  CDS.Open 
except 
  on E: Exception do begin
    ShowMessage(E.Message);
    // optionally Exit, Abort or what else, to stop execution of the next statements
  end;
end;

【讨论】:

【参考方案3】:

我不清楚为什么要在 TClientDataSet 上设置命令文本。我相信如果你设置了 TAdsQuery.SQL 属性,然后打开 TClientDataSet,你会得到你正在寻找的行为。

当我设置它并运行您的代码时,我得到了异常“不允许更改 CommandText”。

procedure TForm57.Button1Click(Sender: TObject);
begin
  try
   CDS.CommandText := 'SELECT * FROM tablename WHERE fieldname = 1';
   CDS.Open;
  except
    on E : Exception do
      ShowMessage( 'got it:' + E.message );
  end;
end;

【讨论】:

好点子,我不知道将 ClientDataset 的 CommandText 设置为与 AdsQuery 的 SQL 相反可能会有什么不同。我会调查的。也许当时我只是认为应用程序不必了解底层数据库会更好。我这样做是为了修改 ClientDataset 中的 CommandText,您必须打开 DataSetProvider 中的 poAllowCommandText 选项。如果您不这样做,则会收到“不允许更改 CommandText”错误。【参考方案4】:
    要执行 SQL 命令,您必须使用 TAdsQuery 而不是 TAdsTable。 奇怪的是,TAdsTable 没有返回错误。正如它应该说的“未知表”之类的东西。 捕获错误并将其报告给用户:
    
        try 
          CDS.CommandText := 'SELECT * FROM tablename WHERE fieldname = 1'; 
          CDS.Open 
        except 
          on E: Exception do begin
            Application.HandleException(Self);
            // optionally Exit, Abort or what else, to stop execution of the next statements
          end;
        end;
    
    没有简单的方法来验证 SQL 查询的语法。因为,那么您将需要重现 DBMS 解析器行为,这是一项复杂的编程任务。更简单的是向 DBMS 提交命令,希望它是正确的(乐观的方法)。

【讨论】:

抱歉,我的意思是说 Provider 与 AdsQuery 相关联,而不是与 AdsTable 相关联。异常的形式应该不是问题。如果您想捕获每种类型的异常,则不必有“on Exception”子句。

以上是关于捕获 TClientDataSet.CommandText 中的错误的主要内容,如果未能解决你的问题,请参考以下文章

捕获组之前或捕获组之后的正则表达式,具有单个捕获组

第18课 捕获机制及陷阱

为啥基类捕获块捕获派生类对象?

为啥使用 Bash 只读变量捕获输出无法捕获返回码 $?

Java 正则表达式之捕获组

在 C++ 中通过指针捕获异常