databaseManager.hasRecordChanges() returns true

Hi all,

We discovered case where a JSRecord (loaded from existing data in the database) contains data different from what is currently in the database but still the databaseManager.hasRecordChanges(record) returns false.

To get to that situation, create 2 separate foundsets based on the same datasource and load the same record in them (using the same PK). Then modify the record in the first foundset and check that the values of the record in the second foundset are updated to match the data in the first foundset. If we check the first foundset it has unsaved changes, however if we do the same for the second foundset, it does not.

function testCase()
{
    //create two separate foundsets using the same datasource
    var dataSource = 'db:/server/table';    
    var fs1 = databaseManager.getFoundSet(dataSource);
    var fs2 = databaseManager.getFoundSet(dataSource);
    jsunit.assertNotSame(fs1, fs2);
    
    //load the same data in both foundsets
    var pk = 1; //this should be some existing PK in the database
    var colName = 'some_column';
    fs1.loadRecords(pk);
    fs2.loadRecords(pk);
    jsunit.assertEquals(fs1.getRecord(1)[colName], fs2.getRecord(1)[colName]);
    
    //change the data in the first foundset
    var originalValue = fs1.getRecord(1)[colName];
    var newValue = 'someNewValue';  
    jsunit.assertTrue(originalValue != newValue);    
    fs1.getRecord(1)[colName] = newValue;    
        
    //both foundset contain the same data which is now different from what is in the database
    jsunit.assertEquals(fs1.getRecord(1)[colName], fs2.getRecord(1)[colName]);
    
    //the first foundset has unsaved changes
    jsunit.assertTrue(databaseManager.hasRecordChanges(fs1));
    //however the second foundset will appear to not have unsaved changes, 
    //even though it now contains data which is different from what is in the database
    jsunit.assertTrue(databaseManager.hasRecordChanges(fs2));
}

I understand that the first and the second foundsets are two different objects and that changes were made only to the first foundset, however as far as the data state is concerned, both foundsets contain the same data after the changes.
In other words, Servoy propagates the data state as expected. Why it is not propagating the fact that this data is changed/is different from the original source in the database? After all both foundsets are in the same client session and in the same thread, and by the looks of it point to the same in-memory data - why one of the foundsets correctly reports that this in-memory data is changed while the other foundset does not?
In my opinion, 99% of the cases when developers are using the methods databaseManager.hasRecordChanges(foundset) they really are checking if the in-memory data referenced by the PKs loaded by that foundset in the client session (and not only in that specific foundset) is different from what is in the database.

So, the question is: since Servoy broadcasts changes to existing data between different foundsets within the same client session, should it also mark all JSRecords which reference the same changed data as “having unsaved changes”?

This is how servoy works, a foundset is only in edit mode when really a record instance of itself is in edit mode.

And if a foundset is in edit then we don’t allow certain stuff because then you could loose those records or they are completely in the wrong place (like sorting on none saved records)

jcompagner:
This is how servoy works, a foundset is only in edit mode when really a record instance of itself is in edit mode.
And if a foundset is in edit then we don’t allow certain stuff because then you could loose those records or they are completely in the wrong place (like sorting on none saved records)

I can take that… but why then the second foundset shows the changed data? Since both foundsets are separate instances and the changes in the first foundset are not saved yet, why do you push the changes to the second foundset? Between different client sessions the changes are broadcasted only when they are saved . However in the case described above the second foundset shows “dirty” data and there is no way we can distinguish that the data in the second foundset is only in-memory and not in the database. Isn’t this misleading?

Its not pushed it is just there

we have Row (which is plain values object 1 per row for a table) and we have Records that are in a selection (foundset)
So the actual data of the table is cached in a Row object for which there is only 1, a record points to such a row and there can be more then 1 record having the same row reference (having the same pk of that table but in different foundsets)

But a record goes into edit mode, and that record is then saved to the database, all other records of that same row just reflects the latest data but are not the one doing the changes.

jcompagner:
Its not pushed it is just there

we have Row (which is plain values object 1 per row for a table) and we have Records that are in a selection (foundset)
So the actual data of the table is cached in a Row object for which there is only 1, a record points to such a row and there can be more then 1 record having the same row reference (having the same pk of that table but in different foundsets)

But a record goes into edit mode, and that record is then saved to the database, all other records of that same row just reflects the latest data but are not the one doing the changes.

Thanks for the explanation - looking at the behavior I suspected that something like that is in the background.

Then, can we have a new method databaseManager.hasRowChanges(record/foundset) which returns true if the rows referenced by the record/records in the foundset have been changed/edited either by the specified record/foundset OR by any other record/foundset which references these rows? Basically what I am after is a deterministic way of figuring out if the field values of a particular record have come from the database OR have been created/changed in the client session (either entered by the user from the UI or changed in code)

problem with that is if you do:

if (databaseManager.hasDbChanges(record)) {
databaseManager.saveData(record)
}

that won’t do a think, because the record itself is not in edit so nothing will be saved…

So that can be tricky to explain then

You could do it already the other way around

databaseManager.getEdittedRecords()

and ask for those records what the changes are…

jcompagner:
problem with that is if you do:

if (databaseManager.hasDbChanges(record)) {
databaseManager.saveData(record)
}

that won’t do a think, because the record itself is not in edit so nothing will be saved…

So that can be tricky to explain then

You could do it already the other way around

databaseManager.getEdittedRecords()

and ask for those records what the changes are…

How about this:
To make things easier to explain then, the method should be named hasRowChanges because the changes are in-memory in the row and not yet in the database and it should return not a Boolean but a value from an enumeration with the following items:
ROW_CHANGES.NONE = there are no in-memory changes
ROW_CHANGES.SELF = there are in-memory changes made by the record/foundset passed as the argument to the method
ROW_CHANGES.OTHER = there are in-memory changes but they are made by another record/foundset which references the same row(s)