使用多个INSERT、UPDATE、..执行SQL脚本时的错误处理,..在Delphi中使用ADO的语句



在执行包含多个INSERT、UPDATE、…的SQL脚本时,我在Delphi/ADO错误处理方面遇到了困难,。。。陈述只有当脚本的第一条SQL语句失败时,我才会在Delphi中得到一个异常。如果第一条语句通过,无论脚本中发生什么,Delphi中都不会出现异常。

这是我使用的Delphi代码:

var
  DataSet: TADOQuery;
begin
  ...
  try      
    DataSet.Close;
    DataSet.ParamCheck := true;
    DataSet.SQL.LoadFromFile(FileName);    
    DataSet.Prepared := true;
    try
      DataSet.ExecSQL;       
    finally    
      DataSet.Close;
    end;
  except
    on E: Exception do        
      Logging.AddText(E.ClassName + ' error raised when executing ' + FileName + '. Message: ' + E.Message);  
  end;      
  ...
end;

为了测试,我使用了这个简单的脚本:

INSERT INTO TESTTABLE
VALUES ('John', 24);
INSERT INTO TESTTABLE
VALUES ('Ed', '32');

其中TESTTABLE只是一个简单的表,包含两列:Name NVARCHAR(50)和Age INT。

例如,当您在第一个INSERT语句中将24替换为"twentyfour"并使用Delphi代码运行脚本时,Delphi/ADO将引发异常。但是,例如,当您在第二个INSERT语句中将32替换为"thirty2"时,也不会出现异常。

我试图通过将脚本放入存储过程"dbo.ErrorHandling"并发送来解决这个问题

EXEC dbo.ErrorHandling

到ADO,但它没有帮助。

CREATE PROCEDURE dbo.ErrorHandling
AS
BEGIN
  INSERT INTO TESTTABLE
  VALUES ('John', 24);
  INSERT INTO TESTTABLE
  VALUES ('Ed', '32');
END

我可以通过在脚本中使用TRY和CATCH来解决这个问题,并让它将错误记录到LOGGING表中。Delphi可以在每次执行脚本后检查此表中的新错误。

然而,是否有可能在Delphi中捕获所有SQL server错误,或者我是否必须执行INSERTS、UPDATES,。。。一个接一个?

我使用DelphiXE6和SQLServer2008R2

我不想看AdoConnection的错误集合。TAdoConnection.Errors

我从未找到任何方法可以同时可靠地处理多个查询并明智地检测问题。我认为正确的解决方案是一次执行一个语句。

这是我的一个程序中的代码,正是J__在评论中描述的。它处理SQL Server风格的脚本,每个语句后面都有一个GO。您可以将"GO"检测器替换为语句结束的其他指示。它将整个事务作为一个要么全有要么全无的事务进行批处理。最后一个有一些代码可以将最后一个查询保存到屏幕上的备忘录中,这样您就可以看到在出现异常时失败了什么。

procedure TDupFrame.LoadButtonClick(Sender: TObject);
var
  Query: TADOQuery;
  Reader: TStreamReader;
  Line: string;
begin
  Query := TADOQuery.Create(nil);
  try
    Query.Connection := ConfModule.ADOConnection;
    Query.Connection.BeginTrans;
    if ScriptOpenDialog.Execute(Self.Handle) then
    begin
      Reader := TStreamReader.Create(ScriptOpenDialog.FileName);
      try
        Query.SQL.BeginUpdate;
        while not Reader.EndOfStream do
        begin
          Line := Reader.ReadLine;
          if not SameText(Line, 'GO') then
          begin
            Query.SQL.Add(Line);
          end
          else
          begin
            Query.SQL.EndUpdate;
            Query.ExecSQL;
            Query.SQL.Clear;
            Query.SQL.BeginUpdate;
          end;
        end;
        Query.SQL.EndUpdate;
        if Query.SQL.Count > 0 then Query.ExecSQL;
      finally
        Reader.Free;
      end;
      Query.Connection.CommitTrans;
    end;
  finally
    SQLMemo.Lines.Assign(Query.SQL);
    // rollback if we have missed the commit (ie an exception occurred)
    if Query.Connection.InTransaction then
      Query.Connection.RollbackTrans;
    Query.Free;
  end;
end;

您需要使用ExecuteNoRecords选项配置TADOQuery或TADOCommand:

Query := TADOQuery.Create(nil);    
Query.ExecuteOptions := [eoExecuteNoRecords];

在.NET中也是如此。如果对SqlCommand使用ExecuteReader()或ExecuteScalar(),则无论后续有多少语句失败,如果单个命令中的第一个语句成功,都不会引发异常。

然而,如果您调用ExecuteNonQuery(),那么在任何情况下都会抛出一个适当的异常。

最新更新