As Ken says, it's difficult to help you without sample code. So I won't be able to answer your question directly, but with a few pointers you may be able to figure it out for yourself. So I'm going to try teach you to fish. ;)
I do have a fair bit of experience with TClientDataSet in Delphi 3 and 6. I doubt things have changed all that much. Plus I'm going to focus more on techniques to kick-start you in the right direction.
First, make sure you compile with Debug DCU's so you can get breakpoints in VCL code. Don't be afraid to read and step through that code - it's a great way to learn. Plus you get to see Borland/CodeGear/Embarcadero's mistakes in all its ugly glory.
I'm assuming you already have Stop on Exceptions enabled (hence why you know you're specifically getting AV errors).
Do your test. When you get your AV, you'll probably come out in DbClient.pas (or perhaps one of the lower level units).
Work your way through the call stack looking for a place where you're within the try part of a try..except block that either swallows the Exception or short-circuits to another handler and then swallows it.
NOTE: DbClient.pas is littered with quite a few instances of the following bad code:
except //swallowing or squashing exceptions is
end; //very dangerous and should be avoided.
except
//short-circuiting to Application.HandleException (usually informs the user)
//but is not much better. The point is the rest of the program up the
//call-stack remains blissfully unaware that something went wrong.
Application.HandleException(Self);
Action := raAbort;
end;
Side comment: Just because Borland did it, doesn't mean it's good practice. You and many others have and will be burned by this.
Once you've found that, you're half-way there. You now know why you're not being informed of the AV.
Now, somewhere within the code that forms part of that call-stack will be a clue to how you're expected to handle the error. You could also place a breakpoint a little earlier in the VCL code so you can step through the to see the sequence of events leading up to the Exception. Since you specifically mentioned AV (Access Violation), look for objects that reference nil.
One example of what could be causing the problem is in the following snippet from D5 DbClient.pas
FOnReconcileError(DataSet, E, UpdateKind, Action);
finally
E.Free;
end;
except
Application.HandleException(Self);
Action := raAbort;
end;
You can see from the above that certain situations require you to implement an OnReconcileError event handler. Without it, the dll won't be given a callback into the above code snippet, and many errors are quietly kicked under the carpet, leaving you scratching your head.
My experience with TClientDataSet is that there were a number of little extra things you had to do to use it "correctly". This was not particularly obvious in the documentation. Though once you figured out all the bits and pieces and pieces you were supposed to do, the examples of how to do them were a little better.
Unfortunately my memory is a little fuzzy as to what all these things were. So this is a verrry rough guide, probably missing quite a bit.
- Consider using an OnReconcileError event handler.
- Consider implementing an UpdateProvider object.
- You mentioned using it as an in-memory dataset, so you're probably using CreateDataSet correctly. But if I remember correctly you had 2 options for specifying the fields, and some of the finer detail attributes were a little picky.
- Unrelated Tip : Be careful with the length of your string fields, TClientDataSet used to (and may still) horde memory in a similar fashion to short strings.
EDIT
Based on additional information in the question and using the technique described above, you are getting an EDatabaseError thrown from the following method.
procedure TIntegerField.SetAsString(const Value: string);
var
E: Integer;
L: Longint;
begin
if Value = '' then Clear else
begin
Val(Value, L, E);
if E <> 0 then DatabaseErrorFmt(SInvalidIntegerValue, [Value, DisplayName]);
SetAsInteger(L);
end;
end;
Higher up the call stack, you get the following method which hints at how to solve the problem.
procedure TField.SetEditText(const Value: string);
begin
if Assigned(FOnSetText) then FOnSetText(Self, Value) else SetText(Value);
end;
Also, if you follow the call stack all the way up to the KeyPress, you'll notice that NO dataset or grid code is involved at all.
The reason your attempts to handle the error in OnPost error didn't work is that you're not getting anywhere near an attempt to Post your record. You're getting a Field Validation error, and the place to handle that is on the field.
Getting back to the hint how to solve the error - you would have to implement a OnSetText event for the field.
HOWEVER I would advise against doing so. The out-the-box behaviour is perfectly acceptable! The user gets an error message explaining what they did wrong, and they get the opportunity to fix it and try again. If they change their mind, they can hit Escape and cancel the edit.
Table1.Active := True
CreateDataSet
already does that (you can check the value immediately after callingCreateDataSet
). Even though this is not the cause of your problem, there's no point in making it Active again! At best it's a waste of time. – Disillusioned