Thanks for the description, it allows me to reproduce what you are seeing. The error message "Record not found or changed by another user" even triggers if SQL_CREATE_COUNTRIES is left unmodified. The problem you describe happens because of a TProvider peculiarity, namely that it does not know how to generate PRIMARY KEYs. It can of course be argued that PRIMARY KEYs can only be generated by the underlying database engine, but it can nevertheless turn out tricky. Still, the DISQLite3_World_ClientDataSet demo also leaves the INTEGER PRIMARY KEY generation to the DISQLite3 engine. To do so, it stores unique negative numbers to ftAutoInc fields. This causes TProvider to exclude INTEGER PRIMARY KEY fields from its INSERT statement so they can be filled in by the DISQLite3 engine: 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); f.AsInteger := FIndex; f.ReadOnly := b; end; end; end; The problem with this approach is that the DISQLite3 engine fills in a value different from the negative one currently stored in the TClientDataSet instance. Therefore the record can no longer be found for DELETEs and UPDATEs. I looked into different ways to solve this dilemma. The easiest is to refresh the TClientDataSet instance after each insert. This reloads all records from the database, including the new and correct INTEGER PRIMARY KEY: 1. Insert New Record 2. Post 3. Apply Updates 4. REFRESH <-- IMPORTANT 5. Delete Record 6. Apply Updates <-- No more error here I also tried to use the TProvider.AfterUpdateRecord event to read the the auto-generated INTEGER PRIMARY KEY from the database with sqlite3_last_insert_rowid() and store it to the dataset like this: procedure TfrmWorld.DataSetProviderAfterUpdateRecord( Sender: TObject; SourceDS: TDataSet; DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind); var b: Boolean; i: Integer; ID: Int64; f: TField; begin if UpdateKind = ukInsert then begin ID := sqlite3_last_insert_rowid(DISQLite3Database.Handle); for i := 0 to DeltaDS.Fields.Count - 1 do begin f := DeltaDS.Fields[i]; if f.DataType = ftAutoInc then begin f.ReadOnly := False; DeltaDS.Edit; f.AsInteger := ID; DeltaDS.Post; // Sadly, this does now work. end; end; end; end; Unfortunately, this fails because the DeltaDS.Post is "Trying to modify read-only field". Sadly, I have not found a way to solve this, as it seems the most reasonable approach. Other than that, the only solution I can think of is that the application creates a unique INTEGER PRIMARY KEY and stores it to the new TClientDataSet record before it applies any updates. If anyone can think of another trick to solve this dilemma, please share! Ralf On 18.08.2011 10:45, edoardo falzetti wrote: > Hallo! > The error is already in your demo application > DISQLite3_World_ClientDataSet.dpr > > You can verify the error in your demo application > DISQLite3_World_ClientDataSet.dpr. > > In it just change the following create: > > SQL_CREATE_COUNTRIES = > 'CREATE TABLE Countries (' + #13#10 + > '"ID" INTEGER PRIMARY KEY,' + #13#10 + > '"Name" TEXT UNIQUE,' + #13#10 + > '"Background" TEXT,' + #13#10 + > '"Area" INTEGER DEFAULT 0,' + #13#10 + //<<<<<< modified: added > DEFAULT > '"Population" INTEGER,' + #13#10 + > '"Birth Rate" FLOAT,' + #13#10 + > '"Life Expectancy" FLOAT,' + #13#10 + > '"Flag" BLOB' + #13#10 + > ')'; > > and then: > > 1) insert new record without editing Area > 2) post > 3) apply updates > 4) delete record > 5) apply updates --> Error > or > 4) edit record > 5) apply updates --> Error > > This is what happens in my transactions where sometimes i have hidden fields > which are for future use and are initialized with the DEFAULT clause. > As all other fields are initialized by the user or, if not, by the program i > saw the error in the field wich was initialized with the default clause. > > But.. > But now trying with your demo i found out that you get the same error even > without the DEFAULT clause if you: > > 1) insert new record WITHOUT editing Area or Population or ... > 2) post > 3) apply updates > 4) delete record > 5) apply updates --> Error > or > 4) edit record > 5) apply updates --> Error > > Just because you already have the project to verify the problem i don't try > now > to extract it from my application. > > But... > > But looking at the errors: > > 'Record changed by another user' > 'unable to find record. No key specified' > > i now remember that these are the very SAME ERRORS i got some months ago but > in > a different context. > At that time i made a project to send you but then i didn't because i found a > solution. > I do not know if it can be of any help, anyway, with the next message i send > you > that project and the solution i found. > > Thanks edoardo > > PS: > - i'be been testing the last version of Disqlite3 with D7. I got the same > wrong > behavior. > - as i told you, the error is the WHERE part of the sql instruction where you > use all the fields but some are not in the state you think they are and the > instruction cannot locate the record. I imagine you use all the fields in the > WHERE because there could be no primary key for the table. But when such > primary key exists, could it not be better to use only the key field in the > WHERE ? > -in demo application DISQLite3_World_ClientDataSet.dpr the DBNavigator wasn't > visible; i had to change the align property of edtbackground and DBNavigator > in > order to use the demo. _______________________________________________ Delphi Inspiration mailing list yunqa@xxxxxxxxxxxxx //www.freelists.org/list/yunqa