1:1 bidirectonally navigable relationship within a singe class/table

13 views
Skip to first unread message

jtuchel

unread,
Aug 23, 2021, 10:10:51 AM8/23/21
to glorp-group

Hi there,

it's me, fighting either Glorp or my ignorance - maybe the latter is more likely, dunno.
I have a class, which is mapped to a single table, and each instance of this class can have a copy of itself. This derived copy lives in the same table and also knows the instance it is a copy of.

So there is my class with these inst vars:
- id
- version
- copy
- original

(an instance can either have a copy or an original, but never both)

The table has the following columns:

* id
* version
* orginal_id
(which means the copy row has a foreign key to the original row in the very same table)

I tried quite a few approaches to map this, but either end up having strange effects when I register: a copy with the session (UpdateCommand gets instantiated instead of InsertCommand, and its owner is the original instead or the copy) , or I get Proxies on UndefinedObjects when reading an original that has no copy.

I thought the best possible way to map this would be this descriptor snippet, but it doesn't work (all objects always get materialized with an invalid Proxy for #copy):

    (aDescriptor newMapping: OneToOneMapping)
        attributeName: #copy;
        referenceClass: MyClass;
            mappingCriteria: (
            Join
                from: (table fieldNamed: 'id')
                to: (table fieldNamed: 'original_id')).
               
 
    (aDescriptor newMapping: OneToOneMapping)
        attributeName: #original;
        referenceClass: MyClass;
        mappingCriteria: (
            Join
                from: (table fieldNamed: 'original_id')
                to: (table fieldNamed: 'id')).




Any ideas what I am doing wrong? What do I have to do to make this work?

Joachim

Esteban Maringolo

unread,
Aug 23, 2021, 10:23:25 AM8/23/21
to glorp...@googlegroups.com
Joachim, 

Can you try using an accessor different to #copy (#backup?) or set the attribute model to use direct access (#useDirectAccess: true).

The #copy selector is problematic in these situations, it's a pseudo-reserved word.

Best regards,

Esteban A. Maringolo

Esteban Maringolo

Senior Software Developer

 emari...@instantiations.com
 @emaringolo
 /emaringolo
 instantiations.com
TwitterLinkedInVAST Community ForumGitHubYouTubepub.dev


--
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 on the web visit https://groups.google.com/d/msgid/glorp-group/e96dee51-0f02-48a6-8763-9fba9ca27978n%40googlegroups.com.

jtu...@objektfabrik.de

unread,
Aug 23, 2021, 10:26:58 AM8/23/21
to glorp...@googlegroups.com
Esteban,


sorry for the confusion. I tried to make a simple example for this post.
In the real code, the variable names aren't #copy and #original. They are #originalRechnung and #stornoRechnung (~original invoice and cancellation invoice), so I think we can assume this is not a name clash...

Joachim



Am 23.08.21 um 16:22 schrieb 'Esteban Maringolo' via glorp-group:
You received this message because you are subscribed to a topic in the Google Groups "glorp-group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/glorp-group/KJDAgAB0fGY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to glorp-group...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/glorp-group/CACCuQm-iN3b04jv-q_aAeib7mjneBgo%3DzDvagh7pE9AjWQ8xoQ%40mail.gmail.com.


-- 
-----------------------------------------------------------------------
Objektfabrik Joachim Tuchel          mailto:jtu...@objektfabrik.de
Fliederweg 1                         http://www.objektfabrik.de
D-71640 Ludwigsburg                  http://joachimtuchel.wordpress.com
Telefon: +49 7141 56 10 86 0         Fax: +49 7141 56 10 86 1


jtu...@objektfabrik.de

unread,
Aug 23, 2021, 10:51:28 AM8/23/21
to glorp...@googlegroups.com
Maybe a better example would be a couple consisting of two Person objects: wife and husband. Let's assume we store the wife_id in the row of the husband.

class: Person

- id
- firstname
- wife
- husband

a person can either have a husband or a wife, but never both. The objects know each other, one of the holding the other in either #husband or #wife.

The table structure:

- id
- firstname
- wife_id


This is the very same scenario: Person references Person 1:1, navigabale from both sides. A husband can find his wife by asking the table for the person with his wife_id, a wife finds her husband by joining on the Person table by using her own id as query key for wife_id of her husband....

Seems so simple, but I always get Person objects with a #wife of nil and #husband being a "Proxy on: UndefinedObject" instead of nil. Although wife_id is nil in all records.

I have a very similar mapping for a hierarchy in place for 1:n where parents and children are in the same table. This has been working for years now, but it seems I can't get this to work for 1:1-relationships.


Joachim


Am 23.08.21 um 16:26 schrieb jtu...@objektfabrik.de:

Alan Knight

unread,
Aug 23, 2021, 12:26:50 PM8/23/21
to glorp...@googlegroups.com
The only thing that seems at all odd to me is that you are mapping from the primary key to a writable mapping. Since it's sufficient for the "original" mapping to exist in order to have that written, you could consider making the relation to copy read-only.

There should certainly be similar examples in the tests - it seems like something pretty fundamental.

jtu...@objektfabrik.de

unread,
Aug 23, 2021, 12:37:28 PM8/23/21
to glorp...@googlegroups.com
Hi Alan,


I tried adding a beReadOnly to the #copy mapping.

Unfortunately, the result is still the same: Primitive failed in: Object:>>#at: due to index out of range. when commiting the UOW.
What's failing is DatabaseRow>>#printLockEqualityForField:on: , because the Database Row has no @oldVersion - which is no surprise, because I created a new object....
The funny thing here is that Glorp Decides to instantiate an UpdateCommand instead of an InsertCommand, although the newly created object is new...

I'll debug further..

Joachim








Am 23.08.21 um 18:26 schrieb Alan Knight:

Alan Knight

unread,
Aug 23, 2021, 1:58:11 PM8/23/21
to glorp...@googlegroups.com
That sounds suspicious to me of having the wrong primary key. Or having a primary key that was right, but set in a way that Glorp didn't expect. Or something to do with primary keys :-) 


jtuchel

unread,
Aug 24, 2021, 11:04:26 AM8/24/21
to glorp-group
Hi Alan,

I've been debugging a little bit further, and first of all just commented out the two mappings for #copy and #original. This still yields the same problem when committing the UOW.
So the first learning here is that the problem is completely unrelated to the mappings, because they're both not present ;-)

Here is what I do when I get these errors:
  1. create a new instance of the same class
  2. set some values from the original objects in the new copy (but leave the id and version empty/nil)
  3. register the new object in the GlorpSession
  4. mySession commitUnitOfWork
The commit fails most of the times, but not always (sic!). When it fails, it is an UpdateCommand which has a DatabaseRow containing the values of the original object (an existing id), but the owner is the new copy (id is nil). These two objects do have different hashes and do answer false to an equality test #=.
Another interesting fact is that the RowMap has no entry for the new row of the copied object...

I'll dig deeper...

Joachim

jtuchel

unread,
Sep 2, 2021, 2:42:49 AM9/2/21
to glorp-group
Hi Alan, Esteban,


it turns out my problem had nothing to do with this relationship mapping at all.
I don't really understand what exactly caused the error, but I found out that doing a refresh: of that newly created immediately after the insert of the copy was responsible for it or at least played an important role in conjunction with some backpointer to a common object being present in both original and copy.
So I don't know the root reason for the problem, but I found a way to avoid it by not refreshing the newly created copy.

The mappings as shown in my initial post is just fine and works like a charm.

Thanks for reading and walking a few steps through this with me.

See you next time I do something stupid with Glorp ;-)

Joachim
Reply all
Reply to author
Forward
0 new messages