[yunqa.de] Re: How to prevent "Key Violation" errors with ClientDataSet

  • From: Delphi Inspiration <delphi@xxxxxxxx>
  • To: yunqa@xxxxxxxxxxxxx
  • Date: Mon, 22 Feb 2010 17:50:58 +0100

At 20:36 20.02.2010, Todd Cary wrote:

>I am using version 3.6.22 and the table definition is
>
>  SQL_CREATE_NOTES =
>    'CREATE TABLE Notes (' + #13#10 +
>    '"ID" INTEGER PRIMARY KEY,' + #13#10 +
>    '"Note" TEXT' + #13#10 +
>    ')';
>
>The field type for the ID field is changed to ftAutoInc, however I do get a 
>Key Violation unless I use the the procedure described below.  Is there some 
>setting in DISQLite3UniDirQuery or DISQLClientDataSet that I may be missing?

TClientDataSet is still a surprising mistery to me. Ironically, I was able to 
reproduce your findings on a newly created project straight away (D7 and 
D2010), but not on the DISQLite3_World_ClientDataSet.dpr, so I thought. But 
surprisingly, I did see exactly one key violation in 
DISQLite3_World_ClientDataSet.dpr (D7 only) out of an estimated 100 or more 
inserts during today's testing.

For what it is worth for, I am glad to report that the problem is not 
DISQLite3. It occurs somewhere deep inside TClientDataSet and, presumably, 
midas.dll far before any information is passed on to DISQLite3. I am not aware 
of any CDS-related options or workarounds; a web search did not turn up 
anything meaningful either.

To suppress the problem, I have added the following procedure to 
DISQLite3_World_ClientDataSet_Form.pas. It targets all ftAutoInc fields in a 
new CDS record and fills them with a unique negative value:

procedure TfrmWorld.ClientDataSet_NewRecord(DataSet: TDataSet);
var
  b: Boolean;
  i: Integer;
  f: TField;
begin
  for i := 0 to DataSet.Fields.Count - 1 do
    begin
      f := DataSet.Fields[i];
      if f.DataType = ftAutoInc then
        begin
          { Set ftAutoInc fields to unique negative values
            to avoid CDS key violations. }
          b := f.ReadOnly;
          f.ReadOnly := False;
          Dec(FIndex); // Integer field.
          f.AsInteger := FIndex;
          f.ReadOnly := b;
        end;
    end;
end;

It should do the job for your's and others' projects as well.

Ralf 

_______________________________________________
Delphi Inspiration mailing list
yunqa@xxxxxxxxxxxxx
//www.freelists.org/list/yunqa



Other related posts: