Glorp misses updates of 1:1 relationships - any ideas?

17 views
Skip to first unread message

jtuchel

unread,
Oct 1, 2025, 2:40:57 AM10/1/25
to glorp-group
Hi there,

I am facing problems with some ToOneRelationships missing updates and although I tried debugging these situations for hours, I found no hint as to what goes wrong. 

Let me explian a little:
I have an object, say customer which has an address. When I update a Customer (existent in the Database) by setting its address (new), most of the times an UPDATE to the Customer is sent to the Database. But in some cases, it seems Glorp misses the change to the #address inst var and doesn't update it the Customer. It does, however, do an INSERT of the new address.... most of the times, but sometimes it even misses this. 
Sometimes, I do the same operation twice and the first one fails and the second works...(???)

So I know I am screaming into an empty echo chamber, but hope dies last ;-)

Does anyone have any experience with this phenomenon? Any ideas what to check specifically? Maybe even a fix on any of the Smallotalks?


Joacihm

 

Alan Knight

unread,
Oct 2, 2025, 10:49:28 AM10/2/25
to glorp...@googlegroups.com
So, what happens in Glorp.
Objects are registered with the unit of work. When they are, Glorp shallow copies them into a Map.
When you commit, it looks for connected objects. So it ought to find the change to that inst var and register the new address.
It takes all the objects it knows about and writes a RowMap. Then it takes the shallow copies and generates a RowMap for them, representing the old state.
Then it looks for differences.
Then it generates SQL for those differences, using an insert if the row wasn't there before, and an update if it was.

So something could be weird with the hashing (the intermittent nature suggests maybe that, but it's a wild guess). But you could try to see if it's happening in terms of the objects, in terms of generating the row map, or in terms of the differences.
There are debugRead and debugWrite properties you can set on the mapping to get you a debugger when it's happening. And I think there might be some logging you could enable, but it's been a while. Or you could add some.


--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to glorp-group...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/glorp-group/77f464e5-6609-4ae9-92f2-a9cdfbbd5e7dn%40googlegroups.com.

jtuchel

unread,
Feb 12, 2026, 10:03:24 AM (8 days ago) Feb 12
to glorp-group
Okay, I thin I now have two related recurring bugs where updates of ToOneRelationships don't work. Another attempt at debugging and I am lost again...

I have an object Receipt that has zero or one ExternalDocument attached to it.This ExternalDocument can have n ExternalFile objects attached to it.
Creating and commiting such a Receipt with an ExternalDocument attached that has 0 or mor attached files to it works like a charm.

A problem arises if I have a Receipt without an ExternalDocument in the database, read it into the image and attach an ExternalDocument with ExternalFiles attached to it and the do a comitUnitOfWork. 
The problem being that the ExternalDocument and its ExternalFiles are always INSERTED into the DB, but the Receipt's EXT_DOC_ID is not UPDATED in about 50% of the cases. I see absolutely no pattern in why this may happen and I somehow cannot find the right place to debug into.

I register: the new ExternalDocument before commitUOW, so it is in the registeredObjects and gets INSERTED. Both ExternalDocument and ExternalFiles get newly assigned IDs and all is fine, it's just that the pointer from the Receipt to the ExternalDocument is not recognized as a change by Glorp.

What I know for sure is that in RowMap>>#additiveDifferencesFrom:into: both rows are equal in the cases where the update doesn't occur. At this point in time, the ExternalDocument does not have an ID yet, so both DatabaseRow objects have a field of EXT_DOC_ID-->nil.
In cases where the UPDATE of Receipt is recognized, the field looks like this: EXT_DOC_ID-->anObject 

I've stepped through the createRows code so many times now and still haven't found the right place to look at...

One interesting observation: a breakpoint in the #build phase seems to lead to an UPDATE in 100% or at least a much higher probability for a correct UPDATE of Receipt...

Does anybody here have any knowledge about such situations, experience on how to debug this properly, or maybe even have a solution in their repository for this?


Joachim

Alan Knight

unread,
Feb 12, 2026, 10:23:34 AM (8 days ago) Feb 12
to glorp...@googlegroups.com
Here's a vague thought. If sometimes the external doc id is nil, because it hasn't been generated, and sometimes it has an ID, that suggests that the order of insert is wrong. Glorp does a topological sort to figure out what the order of operations is. If it can't figure out a valid order, or it isn't doing it correctly, then sometimes it might write the external document first and then it's fine, and sometimes it might not, and then it's bad. Try logging the order of SQL statements and see if there's a consistent difference in the order in the two cases.

jtuchel

unread,
Feb 12, 2026, 10:42:49 AM (8 days ago) Feb 12
to glorp-group
Hi Alan,


the sequence of statements is the same in both cases, just the UPDATE of the Receipt is missing...

This is a good case (Sorry for the mix of German and English Table names. I translated the real Table name to RECEIPT fopr your convenience) :  
2026-02-12 16:10:32,246   select next value for db2inst1.EXTERNESDOKUMENT_id_seq from SYSCAT.TABLES fetch first 1 rows only
2026-02-12 16:10:32,309   INSERT INTO db2inst1.EXTERNESDOKUMENT (id,version,titel,kategorie,firma_id)  VALUES (656150,1,'Buchungsbeleg',98,181)
2026-02-12 16:10:32,309   (0.0 s)
2026-02-12 16:10:32,309   UPDATE db2inst1.RECEIPT SET version = 7,ext_dok_id = 656150 WHERE id = 1110364 AND (db2inst1.RECEIPT.version = 6)
2026-02-12 16:10:32,309   (0.0 s)

2026-02-12 16:10:32,309   UPDATE db2inst1.BUCHUNGSSATZ SET version = 26,zeitstempel = '2026-02-12 16:09:10.919' WHERE id = 2311776 AND (db2inst1.BUCHUNGSSATZ.version = 25)
2026-02-12 16:10:32,309   (0.0 s)
2026-02-12 16:10:32,309   INSERT INTO db2inst1.BUCHUNGSSATZ_HISTORISCH (buchh_id,buchsatz_id,ts,bearbeiter,grund,datum,dat_leistg,buchungstext,ustIDAbnehmer,ktonr_soll,ktobez_soll,betrag_soll,ktonr_haben,ktobez_haben,betrag_haben,mwstcode_id,ktonr_mwst,ktobez_mwst,betrag_mwst,eu_mwst_prozent,eu_land,beleg_id)  VALUES (17602,2311776,'2026-02-12 16:09:10.949','har...@testheimer-werkzeuge.de','Ä','2026-02-11',NULL,'Buchung mit Beleg ohne 2026-02-12 16:10:34,667   Commit Transaction
 

And here is a bad one:

2026-02-12 16:25:47,855   select next value for db2inst1.EXTERNESDOKUMENT_id_seq from SYSCAT.TABLES fetch first 1 rows only
2026-02-12 16:25:47,901   INSERT INTO db2inst1.EXTERNESDOKUMENT (id,version,titel,kategorie,firma_id)  VALUES (656151,1,'Buchungsbeleg',98,181)
2026-02-12 16:25:47,918   (0.015 s)
2026-02-12 16:25:47,934   UPDATE db2inst1.BUCHUNGSSATZ SET version = 27,zeitstempel = '2026-02-12 16:25:45.386' WHERE id = 2311776 AND (db2inst1.BUCHUNGSSATZ.version = 26)
2026-02-12 16:25:47,948   (0.0 s)
2026-02-12 16:25:47,965   INSERT INTO db2inst1.BUCHUNGSSATZ_HISTORISCH (buchh_id,buchsatz_id,ts,bearbeiter,grund,datum,dat_leistg,buchungstext,ustIDAbnehmer,ktonr_soll,ktobez_soll,betrag_soll,ktonr_haben,ktobez_haben,betrag_haben,mwstcode_id,ktonr_mwst,ktobez_mwst,betrag_mwst,eu_mwst_prozent,eu_land,beleg_id)  VALUES (17602,2311776,'2026-02-12 16:25:45.464','har...@testheimer-werkzeuge.de','Ä','2026-02-11',NULL,'Buchung mit Beleg ohne Anhang','','1800','Bank',50,'1610','Kasse 1',50,NULL,NULL,NULL,0,NULL,NULL,1110364)
2026-02-12 16:25:50,308   Commit Transaction

In both cases, I had attached a new externaldocument to the Receipt and committed.

In case #1 the two DatabaseRow objects differ in RowMap>>#additiveDifferencesFrom:into:. 

I tried to trick Glorp by changing the timestamp in the Receipt before committing when I attach an ExternalDocument, but even this doesn't trigger an UPDATE. 
I also made sure that the Object in memory always has the externesDokument inst var set correctly during the whole preCommit phase and afterwards. Since I do a refresh after the commit, the variable gets reset to nil by the refresh. I can see that the database row has a NULL after the commit and before the refresh (anything else would be a miracle given the sql statements (not) being issued).

I'll keep digging. Thanks for your input anyways. I need to find out where the Row for the changed object is being created and when/where it would get updated with the id of the INSERTED ExternalDocument. Maybe when I get there, I will understand why it is not updated in some cases.
If nothing helps. I will probably have to somehow make this a seqzuence of two commits, something that refreshes the external document from the db and brutally sets its id in the Receipt in a second commit.... Cowardish and hard to document/underastand in maintenance mode, but the bug itself is annoying enough to justify even ugly hacks.

Alan Knight

unread,
Feb 12, 2026, 11:26:10 AM (8 days ago) Feb 12
to glorp...@googlegroups.com
Ah well. So the other thing you might try is there's a debugWrite attribute you can set on a mapping that would get you into a debugger where that value is being written to each rowMap. So either it's not getting written correctly, or that value is incorrect in the object.
One possible issue is with object identity. The rowmap difference is done by taking shallow copies of the objects before they are changed, and generating rows from them, and also generating rows from the actual objects, and computing the difference. If it thinks the object hasn't changed, then it might be because
a) the copy has null, the real object points to the new object, but the new object it points to either doesn't have the id field populated, or else the mapping isn't correctly writing it
b) the copy has null, the real object also has null - seems unlikely, but there could be something weird going on
c) the copy ALSO has the new object. This might happen if there's something funny going on with the identity of the objects - wrappers, proxies, I don't know. And you're in VA, where the object copying works a bit differently, there could be a bug there.
But inspecting the values that mapping is operating on in both the old map and the new map should tell you which scenario it is, if that's where the problem lies.

Reply all
Reply to author
Forward
0 new messages