Using Strongly Typed Datasets; On Unique Key exception in edit - current record moves to first

Hi, Using Delphi client and C# Server, using strongly types datasets in Delphi.
When we put a record in insert and show an edit form, then type in something existing against a a field set up as unique. We Post then applyupdates(F,T) - on exception it moves to the 1st record. We want to cancel the post - but stay on the record being inserted. How do we do this?

Also where is it the best place to trap these type of exceptions?.. FK’s/Uniques etc and supply the exception message - we do not want to use the ShowReconcile, but just handle the exception for our users.

Good question, I did a similar one and they simply mentioned logged as #xxxx. I was expecting that the duplicate keys, indexes, etc will be detected on the client side without having to applyupdates and that there will be a way (an event like in the TClientDataSet) that we can use to manage the error with no reconciliation dialog.

It is a fairly common situation so I’m a bit confused on why it is not there. Anyone on RO with more comments on it?

Hi there, is there answer to this… it has been here for six days! cheers.

Hello,
Sorry for delay.
You wrote:

We want to cancel the post - but stay on the record being inserted. How do we do this?
Please use TDAMemDataTable.CancelUpdates methos to cancel changes.

on exception it moves to the 1st record.
Can you send us a small testcase which reproduces this behavior?

Also where is it the best place to trap these type of exceptions?
The simple way is using reconcile events for this purpose, but don’t show reconcile dialog. Change error message
for users in TDARemoteDataAdapter.OnGenerateRecordMessage event.

Hi,

I have created a sample project, set up as the same as ours - it reproduces the issue of setting up a master detail relationship - inserting a details record on a table that a has a unique index - capturing the message as you described and cancelling the changes makes it go to the first detail record… which is the issue.

But I found if I unhook master detail and manually set the Id of the master onto the detail record at insert then the edit fails but stays on the data i entered… which is correct.

I have attached a client in Delphi, a Server in C# VS2010, a Database scripts - all you have to do is setup you database username/password in the connections in VS for the database. We are using the latest RO for both Delphi and VS. See attached.

Also… ReturnToCurrentRecord does not work in Master -> Detail, the detail goes to a record, NOT the one just inserted.

Hello,
Thanks, the issue was logged as #53870

Thanks thought it was a bug! What is the ETA for this as this is a very urgent fix for us.

Now for me to get around unique key constraints I guess I have to resort to firing off a SQL ‘‘íf exists’’ prior to a post/apply-updates… is this best way to go about it?

thanks for your time on this.

Also... ReturnToCurrentRecord does not work in Master -> Detail, the detail goes to a record, NOT the one just inserted.

is this also logged in the same defect? as if we insert without error the cursor does NOT reposition on to the new record… not matter what we do.

issue was logged as #53870

sorry for the impatience - but can I get answer here - is there a way to escalate these messages?

Hello,
Sorry for delay.
We are working on it now. We will send you a workaround at the nearest time.

Hi, is there an update ready yet, it’s been almost 2 weeks.

cheers.

Hello,
Please apply the following workaround:

uDADataTable.pas

procedure TDADataTable.MergeDelta;
var
.....................
bm: TBookmark;
.....................
// Disables the M/D relationship so that Locates can work in all cases (master or detail tables, regardless
      // of their positioning)
      //if not (ruoOnPost in oldopt) then MasterSource := NIL;
      if not (ruoOnPost in oldopt) then begin
        MasterSource := NIL;
        bm := GetBookmark;
      end;
......................
// Restores the M/D relationship
        //if not (ruoOnPost in oldopt) then MasterSource := oldmastersource;
        if not (ruoOnPost in oldopt) then begin
          MasterSource := oldmastersource;
          if BookmarkValid(bm) then GotoBookmark(bm);
        end;

Thanks, I have to test further but at the moment it is not working all the time. Not sure if this is due to Grid sorts etc. BUT if I have a valid bookmark why is this code firing - it is in the middle of the two blocks you provided above - if bookmark is valid - why go to first and then locate??? - is this now redundant in some form?

          // Locates the original record
          First;
          if not Locate(pkfields, keyvals, []) then begin
            if Assigned(fOnMergeDeltaUnknownChange) then fOnMergeDeltaUnknownChange(Self, fDelta,Delta[i]);
            Continue;
          end;

I Will provide more feedback once I Have worked through any grid issues - but at the moment it is NOT fully functional - ie some times it goes to the new record, sometimes it doesn’t - 50/50.

OK, I have included your fix and found an issue with it as it work intermittently - so I amended another block of code to this and it works fine now


          for k := 0 to (key_cnt-1) do
            keyvals[k] := Delta[i].OldValueByName[keynames[k]];

          // Locates the original record
          if not (ruoOnPost in oldopt)
          and (BookmarkValid(bm)) then
          begin
            if Assigned(fOnMergeDeltaUnknownChange) then fOnMergeDeltaUnknownChange(Self, fDelta,Delta[i]);
              Continue;
          end
          else begin
            First;
            if not Locate(pkfields, keyvals, []) then begin
              if Assigned(fOnMergeDeltaUnknownChange) then fOnMergeDeltaUnknownChange(Self, fDelta,Delta[i]);
            Continue;
          end;
          end;

Thank you so much for providing a part solution, it pointed to me the right area!

cheers.

OK, I have included your fix and found an issue with it as it work intermittently - so I amended another block of code to this and it works fine now
          for k := 0 to (key_cnt-1) do
            keyvals[k] := Delta[i].OldValueByName[keynames[k]];

          // Locates the original record
          if not (ruoOnPost in oldopt)
          and (BookmarkValid(bm)) then
          begin
            if Assigned(fOnMergeDeltaUnknownChange) then fOnMergeDeltaUnknownChange(Self, fDelta,Delta[i]);
              Continue;
          end
          else begin
            First;
            if not Locate(pkfields, keyvals, []) then begin
              if Assigned(fOnMergeDeltaUnknownChange) then fOnMergeDeltaUnknownChange(Self, fDelta,Delta[i]);
            Continue;
          end;
          end;

Thank you so much for providing a part solution, it pointed to me the right area!

cheers.

Hello,

OK, I have included your fix and found an issue with it as it work
intermittently - so I amended another block of code to this and it works fine now

Cursor should move to first changed record when error occurs, but not to current.
Try to test your workaround with the following steps:

  1. Change some records
  2. Move to any unchanged record
  3. Do ApplyUpdate

why go to first and then locate
In some cases datasets can start searching with the current record (ADO or CDS) in Locate.