Question

In some situation (in a multi-user environment) when I Edit a TADODataSet and Post it, I get an Exception raised by ADO:

"Row cannot be located for updating. Some values may have been changed since it was last read."

If I run my program from the IDE the exception is raised as EOleException with Error number -2147217864.
I want to be able to catch this exception, but when I run the program outside the IDE the exception is raised as EDatabaseError which does not have the ErrorCode I need to examine. Here is part of my code:

procedure TForm1.DataSetCommit(ds: TADODataSet);
begin
  ds.Connection.BeginTrans;
  try    
    try
      ds.Post; // <- Exception is raised here
    except
      on E: EOleException do; // EOleException is NOT fired! (E.ErrorCode = -2147217864) - see "ADODB.TCustomADODataSet.InternalPost"
      on E: EDatabaseError do 
      begin
        // todo: Handle this situation
      end;
    end;
    ds.Connection.CommitTrans;
  except
    ds.Connection.RollbackTrans;
    raise;
  end;
end;

If you look in ADODB.TCustomADODataSet.InternalPost you will notice that it's wrapped as so:

procedure TCustomADODataSet.InternalPost;
begin
  UpdateCursorPos;
  try
    ... // <- Exception is raised here
  except
    on E: Exception do
      DatabaseError(E.Message);
  end;
  CheckForFlyAway;
end;

The exception is raised inside the local procedure UpdateData: Recordset.Update(EmptyParam, EmptyParam); which triggers a EOleException (what I need) but the wrapper raises EDatabaseError! (grrrrrrr).

My question is how do I get my hands on the original EOleException so I can query EOleException.ErrorCode?

Was it helpful?

Solution

I've tried to utilize the System.RaiseList to get the TRaiseFrame.NextRaise to no avail - I'm not getting the desired EOleException... So I found a rather elegant solution which is specific to my case (ADO) and does not rely on the RTL - I'm testing the Errors object of the TADODataSet.Connection:

procedure TForm1.DataSetCommit(ds: TADODataSet);
begin
  ds.Connection.BeginTrans;
  try      
    try
      ds.Post;
    except          
      on E: EDatabaseError do 
      begin          
        if Assigned(ds.Connection.Errors) and (ds.Connection.Errors.Count > 0) then
          with ds.Connection.Errors.Item[0] do
            // if (Number = -2147217864) then ...
            ShowMessage(Format('Number:%d; Source:%s; Description:%s; NativeError:%d; SQLState:%s',
              [Number, Source, Description, NativeError, SQLState]));
      end;
    end;
    ds.Connection.CommitTrans;
  except
    ds.Connection.RollbackTrans;
    raise;
  end;
end;

This will be my solution to the specific problem, but I'm still interested in other ideas on how to trap the previous exception of EOleException.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top