Prodataset transaction question

Posted by ericg on 12-Feb-2009 14:54

Hi there. I am providing a Get and a Set procedure via a DLL to a .NET client. The Get initiates the INPUT-OUTPUT dataset using a FILL() and then sets TRACKING-CHANGES to TRUE. Then the client make changes to the dataset and then calls the Set procedure which eventually performs a SAVE-ROW-CHANGES().

This has worked well, however now the client wants to have the same data sent back that would include any field validation issues that was REJECTed during the Set. That is fine since I just make a copy of the after table before doing any validation and saving valid rows to the DB, then empty the after table and populate it with the copy.

But now on subsequent calls I have to not refill the dataset/after table (using FILL()) but still start tracking changes (using TRACKING-CHANGES). So in my Get I have extra logic to not run the FILL() on subsequent calls.

But I receive the error below after the second Set call. Any suggestions?

SAVE-ROW-CHANGES found record with conflicting change by another user. (11913)

The record in the database may have been deleted or changed by another user since the dataset has been first filled. If the data-source has the RECONCILE-CURRENT-CHANGES attribute true, and you are not deleteing the record, then the change in the database table must be on the same field as was changed in the dataset table to cause this error.

All Replies

Posted by Håvard Danielsen on 13-Feb-2009 12:03

Hi there. I am providing a Get and a Set procedure

via a DLL to a .NET client. The Get initiates the

INPUT-OUTPUT dataset using a FILL() and then sets

TRACKING-CHANGES to TRUE. Then the client make

changes to the dataset and then calls the Set

procedure which eventually performs a

SAVE-ROW-CHANGES().

The before-image table will still have the old values from the fill() after save-row-changes(), so a subsequent save will cause an optimistic lock conflict. You typically use accept-changes (or accept-row-changes) to make the after-image table the current version (and remove the before-image table) before you allow the client to make new changes. There are equivalent reject- methods to roll the change back.

This has worked well, however now the client wants to

have the same data sent back that would include any

field validation issues that was REJECTed during the

Set. That is fine since I just make a copy of the

after table before doing any validation and saving

valid rows to the DB, then empty the after table and

populate it with the copy.

I assume you do this only when the row is rejected or has an error? It should be unnecessary when the save is successful and it could even be wrong since you’d miss any changes done by triggers (or changes done by other users if you use reconcile-current-changes).

I'm not fully understanding what you are trying to resolve. I believe you will have the data intact if a save is rejected (?), but optimistic locking conflicts may require you to keep track of the old value, depending on the client’s requirements, since both the before and after image table will have the new values.

If you really need a copy of the submitted changes to ensure proper error feedback, you might consider using extract-changes to make a copy dataset with changes only and pass this to save-row-changes and then use merge-changes (merge-row-changes) to get them back to the original dataset. This should ensure that you get the refreshed values from the database while honoring the reject and error flags. Note that there still might be cases where a manual copy gives better control. It all depends on your client's error and conflict resolution requirements.

Posted by ericg on 13-Feb-2009 13:09

Havard, I do not get the mentioned 11913 error anymore when I changed SAVE-ROW-CHANGES to ACCEPT-ROW-CHANGES. However row changes are not saved/accepted to the DB! So I went back to using SAVE-ROW-CHANGES.

What I am trying to do is:

Client call Get procedure:

Initial FILL.

TRACKING-CHANGES = TRUE.

Data set is returned to client.

Client performs some modifications (inserts or updates or deletes).

Client calls Set procedure:

Copy after table (because client wants the same rows and edited values returned).

Some validation logic.

TRACKING-CHANGES = FALSE.

SAVE-ROW-CHANGES to every before table row.

Replace after table rows with the copy.

TRACKING-CHANGES = TRUE.

Data set returned to user.

Client performs some more record changes.

Set procedure is called again.

Posted by ericg on 13-Feb-2009 13:23

I queried the before table, before calling the Set procedure and there are entries to every row change. So the before table is correct. This is when using ACCEPT-ROW-CHANGES.

Posted by Håvard Danielsen on 13-Feb-2009 13:26

You do not use accept-row-changes instead of save-row-changes. You just need to do it somewhere before you set tracking-changes back on and allow the user to update the data again. I don't think it makes sense to do this inside of the transaction even, as the accept is really a client side operation (or at least an operation for the client).

Posted by ericg on 13-Feb-2009 15:43

Okay. If I recieve a record (in the Set procedure) that I REJECT-ROW-CHANGES, then later recieve the same record but is acceptable, on SAVE-ROW-CHANGES Progress still gives me the same mentioned error. I am also doing a manual copy of the after table before any validation or saving then copy back to the after table before leaving the procedure, so the client can still recieve the rejected rows. But Progress do no like this.

So I will try what you mentioned:

"

If you really need a copy of the submitted changes to ensure proper error feedback, you might consider using extract-changes to make a copy dataset with changes only and pass this to save-row-changes and then use merge-changes (merge-row-changes) to get them back to the original dataset. This should ensure that you get the refreshed values from the database while honoring the reject and error flags. Note that there still might be cases where a manual copy gives better control. It all depends on your client's error and conflict resolution requirements.

"

Message was edited by:

Eric K

Posted by Håvard Danielsen on 13-Feb-2009 20:03

Okay. If I recieve a record (in the Set procedure)

that I REJECT-ROW-CHANGES, then later recieve the

same record but is acceptable, on SAVE-ROW-CHANGES

Progress still gives me the same mentioned error.

What is the condition of the record before you reject-row-changes and when/where do you do this?

am also doing a ms?anual copy of the after table before

any validation or saving then copy back to the after

table before leaving the procedure, so the client can

still recieve the rejected rows. But Progress do no

like this.

As far as I understand the only case where you might need to do extra work to return submitted data to the client would be when you have an optimistic locking conflict (i.e. when you get the mentioned error for the real reason) and the client want both old and new data to allow the user to resolve the conflict without loosing changes. (The client should really/ideally keep the submitted data on the client until they are successfully saved if this is a requirement.)

I might very well be missing something here. Can you clarify when you do this and what the client requirements are?

Posted by ericg on 15-Feb-2009 18:51

Hi. Okay, If I may. I think I am getting closer to a solution to my problem of sending back the dataset which includes any rejected rows (errors) to the client in what you described earlier:

If you really need a copy of the submitted changes to ensure proper error feedback, you might consider using extract-changes to make a copy dataset with changes only and pass this to save-row-changes and then use merge-changes (merge-row-changes) to get them back to the original dataset. This should ensure that you get the refreshed values from the database while honoring the reject and error flags. Note that there still might be cases where a manual copy gives better control. It all depends on your client's error and conflict resolution requirements.

So originally I have:

FOR EACH OriginDatasetBeforeTable:

/I do some row and field auditing here/

BUFFER OriginDatasetBeforeTable:SAVE-ROW-CHANGES().

END.

But now according to your comment, how do I replace OriginDatasetBeforeTable with the Changed dataset before-table? In other words, how do I access the Changed dataset before-table?

Message was edited by:

Eric K

Posted by ericg on 15-Feb-2009 19:53

I should mention also that now before I do any validation checking and using REJECT-ROW-CHANGES to the Origin dataset, I have the following code:

DEFINE VARIABLE ChangesDatasetHandle AS HANDLE NO-UNDO.

CREATE DATASET ChangesDatasetHandle.

ChangesDatasetHandle:CREATE-LIKE(DATASET OriginDataset:HANDLE ).

ChangesDatasetHandle:GET-CHANGES(DATASET OriginDataset:HANDLE).

/* Validation and possible row rejecting done here on the OriginDatasetBeforeTable*/

And after the SAVE-ROW-CHANGES block I have:

ChangesDatasetHandle:MERGE-CHANGES(DATASET OriginDataset:HANDLE).

DELETE OBJECT ChangesDatasetHandle.

TEMP-TABLE OriginDatasetTempTable:TRACKING-CHANGES=TRUE.

END /* Set */ PROCEDURE.

But I get an error when testing a rejected row: INVALID origin-rowid of the change table . (11928)

on the MERGE-CHANGES statement.

Posted by Håvard Danielsen on 16-Feb-2009 09:26

When you reject the changes you make the after-image table the current version and remove the before-image table, so one of the origin-handles will be gone. It is a client operation (or an operation for the client), so if you do it on the server it should be the last thing you do to this record on the server. But I doubt you really want to reject records that fail validation on server, since this makes it very hard to detect that something went wrong on the client.

The best way to handle validation is to mark the rows by setting the error or rejected flag on the server and then use these flags on the client somehow.

I suspect that both your original attempt to do manual copying and the use of extract changes on the server are overkill. I'm pretty sure we can find a simpler solution if you explain the client requirements.

Posted by ericg on 16-Feb-2009 10:57

Hi. It is a .NET client. They would like to receive a dataset to include the user edited rows (with the field values they edited) that have business logic errors found on the server-side (such as a blank field). So those are the ones I am using REJECT-ROW-CHANGES and the other changed records they are good I use SAVE-ROW-CHANGES.

Posted by ericg on 16-Feb-2009 11:33

Havard, I think I found a solution. I just do not use REJECT-ROW-CHANGES and simply make a copy of the record to a temp-table during validation. Then during SAVE-ROW-CHANGES block I first check to see if there is a record in my temp-table. If so, then I do not do anything and the row is still in the dataset to be returned. It seems to be working. I will test more.

Posted by Håvard Danielsen on 16-Feb-2009 11:49

Yes, returning the record back as it was should work. I still think you would be better off just setting the record's error or rejected attribute (instead of copying the table on the server). This would require that the client turns the attribute off again before allowing new changes, but you need to do something to distinguish the rejected changes anyways.

This thread is closed