Domanda

I have a DataSnap method that logs a deleted record before it is deleted. If the delete fails, I rollback the transaction so that the log record isn't kept either. A classic reason for a failure is that the record that is being deleted is in use in another table.

My SQL looks similar to this:

begin transaction
begin try
  insert into audit ([fields]) values ([the vlaues])
  delete [sometable] where [id] = [someid]
  commit transaction
end
begin catch
  rollback transaction
end catch

This works just fine. However, the error message is suppressed so the DataSnap server never sees it. SQL syntax errors always surface error message, and other insert / update unique and foreign key violations always return an error. I don't understand why this code suppresses the error. The DataSnap code is simple:

procedure TMyClass.DeleteRecord([params]);
var
  qry: TSQLQuery;
begin
  qry := TSQLQuery.Create;
  ...
  qry.CommandText := [sql from above];
  qry.ParamByName('[params]').Value := [Values];
  qry.ExecSQL; // <- No error is raised here
end;

The query executes just fine so there are no syntax errors or problems with binding the parameters. I just never see the foreign key violation error. When I run the SQL in SQL Management Studio, I always see the error... So I tried changing the catch block as follows:

try catch
  rollback transaction
  raiserror(N'Test Error Message', 16, 1)
end catch

I still do not see an error raised when debugging the DataSnap Server, so of course the client app knows nothing of the error. Does anyone have any ideas why the 'raiserror' and the foreign key violation error(s) do not surface in the DataSnap server?

FYI - I'm using Delphi XE2 Enterprise and SQL Server 2008 R2 all running on Windows Server 2008 R2.

È stato utile?

Soluzione

The solution ended up being very simple. Adding set nocount on; at the start of the SQL statement fixed the issue that hid the error from DataSnap. I've seen this before -- but mainly when data is returned. Since this uses qry.ExecSQL();, it didn't occur to me that nocount was needed here too.

Here is the code I use to reraise the SQL error after rolling back the transaction:

set nocount on;
begin transaction
begin try
  insert into audit ([fields]) values ([the vlaues])
  delete [sometable] where [id] = [someid]
  commit transaction
end
begin catch
  declare @eMsg nvarchar(2048), @eSv int, @eSt int
  select @eMsg = error_message(), @eSv = error_severity(), @eSt = error_state()
  rollback transaction
  raiserror(@eMsg, @eSv, @eSt)
end catch

Now the reraised error displays in the client application as desired.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top