Problem with inheritance and polymorphic query

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Problem with inheritance and polymorphic query

Abel Armoa
Hello again:

I found a new problem while preparing the persistence in my application, and I wanted to ask if any of you had already experienced the same problem (and how could you solve it). I am currently using VA Smalltalk 8.6.1.

The problem arises when configuring the persistence of a hierarchy in one table. I will explain the problem with a simplified example.

I have the class Parent with two subclasses: LeftChild and RightChild. Parent is abstract, and has two instance variables: top and id. ID is the key of the objects, and is assigned using a sequence.

Object subclass: #Parent
instanceVariableNames: 'top id'
 
Parent subclass: # LeftChild
instanceVariableNames: 'left referencedObject'
 
Parent subclass: #RightChild
instanceVariableNames: 'right referencedObject'


The information of this hierarchy's instances is persisted in the table ALL_DATA

And the important detail is that referencedObject is instance of ReferencedObject:

Object subclass: #ReferencedObject
instanceVariableNames: 'oneValue '

I configured this class to be persisted using an imaginary table (IMAGINARY_REFERENCED_OBJECT), and the mapping in the descriptors of both LeftChild and RightChild was specified using an EmbeddedValueOneToOneMapping.

With this configuration Glorp always fails when I try to bring all the elements of Parent (session read: Parent). The problem seems to be that in EmbeddedValueOneToOneMapping>>mapObject: anObject inElementBuilder: anElementBuilder, the framework tries to get the Builder for Base(Parent).referencedObject looking for it between the mappings of Parent. And when it does not find it, it ends up trying to send the message "instance" to nil.

I will next paste all of the SystemDescriptor configuration for you to see.

Thank your very much for your help,
Abel Armoa

_____________________________________________________________


allTableNames
^#('ALL_DATA' 'IMAGINARY_REFERENCED_OBJECT')
 
 
______________________________________________________________

classModelForLeftChild: aClassModel

aClassModel newAttributeNamed: #left.
aClassModel newAttributeNamed: #top.
aClassModel newAttributeNamed: #id.
aClassModel newAttributeNamed: #referencedObject type: ReferencedObject

______________________________________________________________

classModelForReferencedObject: aClassModel
   
   aClassModel newAttributeNamed: #oneValue.

_______________________________________________________________

classModelForRightChild: aClassModel

aClassModel newAttributeNamed: #right.
aClassModel newAttributeNamed: #top.
aClassModel newAttributeNamed: #id.
aClassModel newAttributeNamed: #referencedObject type: ReferencedObject

________________________________________________________________

constructAllClasses

^(super constructAllClasses)
add: Parent;
add: LeftChild;
add: RightChild;
add: ReferencedObject;
yourself

________________________________________________________________

descriptorForLeftChild: aDescriptor

| leftTable |

leftTable := self tableNamed: 'ALL_DATA'.
aDescriptor table: leftTable.
(aDescriptor newMapping: DirectMapping) from: #id to: (leftTable fieldNamed: 'id').
(aDescriptor newMapping: DirectMapping) from: #top to: (leftTable fieldNamed: 'top_value').
(aDescriptor newMapping: DirectMapping) from: #left to: (leftTable fieldNamed: 'left_value').
(aDescriptor newMapping: EmbeddedValueOneToOneMapping)
attributeName: #referencedObject;
fieldTranslation: (
(Join new)
addSource: (leftTable fieldNamed: 'referenced_object')
target:
((self tableNamed: 'IMAGINARY_REFERENCED_OBJECT') fieldNamed: 'one_value');
yourself).

(self typeResolverFor: Parent)
register: aDescriptor
keyedBy: 'L'
field: (leftTable fieldNamed: 'object_type')

___________________________________________________________________

descriptorForParent: aDescriptor

| table |

table := self tableNamed: 'ALL_DATA'.
aDescriptor table: table.
(aDescriptor newMapping: DirectMapping) from: #id to: (table fieldNamed: 'id').
(aDescriptor newMapping: DirectMapping) from: #top to: (table fieldNamed: 'top_value').
(self typeResolverFor: Parent) register: aDescriptor abstract: true

____________________________________________________________________

descriptorForReferencedObject: aDescriptor
 
   | table |
   table := self tableNamed: 'IMAGINARY_REFERENCED_OBJECT'.
   aDescriptor table: table.
   (aDescriptor newMapping: DirectMapping) from: #oneValue
 to: (table fieldNamed: 'one_value').

____________________________________________________________________

descriptorForRightChild: aDescriptor

| rightTable |

rightTable := self tableNamed: 'ALL_DATA'.
aDescriptor table: rightTable.
(aDescriptor newMapping: DirectMapping) from: #id to: (rightTable fieldNamed: 'id').
(aDescriptor newMapping: DirectMapping) from: #top to: (rightTable fieldNamed: 'top_value').
(aDescriptor newMapping: DirectMapping) from: #right to: (rightTable fieldNamed: 'right_value').
(aDescriptor newMapping: EmbeddedValueOneToOneMapping)
attributeName: #referencedObject;
fieldTranslation: (
(Join new)
addSource: (rightTable fieldNamed: 'referenced_object')
target:
((self tableNamed: 'IMAGINARY_REFERENCED_OBJECT') fieldNamed: 'one_value');
yourself).
(self typeResolverFor: Parent)
register: aDescriptor
keyedBy: 'R'
field: (rightTable fieldNamed: 'object_type')

______________________________________________________________________

tableForALL_DATA: aTable

(aTable createFieldNamed: 'top_value' type: (platform varChar: 50)).
(aTable createFieldNamed: 'left_value' type: (platform varChar: 50)).
(aTable createFieldNamed: 'right_value' type: (platform varChar: 50)).
(aTable createFieldNamed: 'object_type' type: (platform varChar: 2)).
(aTable createFieldNamed: 'id' type: (platform sequence)) bePrimaryKey.

(aTable createFieldNamed: 'referenced_object' type: (platform varChar: 50))

_______________________________________________________________________

tableForIMAGINARY_REFERENCED_OBJECT: aTable

aTable name: 'IMAGINARY_REFERENCED_OBJECT'.
aTable isImaginary: true.
(aTable createFieldNamed: 'one_value' type: (platform varChar: 50))

_______________________________________________________________________

Parent class>>#glorpTypeResolver

^FilteredTypeResolver forRootClass: Parent

 
 

--
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 [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Problem with inheritance and polymorphic query

Alan Knight-2
See my immediately previous answer for the bit about base expression/descriptor not being set yet when the query tries to make use of it.

On Mon Feb 02 2015 at 8:57:54 AM Abel Armoa <[hidden email]> wrote:
Hello again:

I found a new problem while preparing the persistence in my application, and I wanted to ask if any of you had already experienced the same problem (and how could you solve it). I am currently using VA Smalltalk 8.6.1.

The problem arises when configuring the persistence of a hierarchy in one table. I will explain the problem with a simplified example.

I have the class Parent with two subclasses: LeftChild and RightChild. Parent is abstract, and has two instance variables: top and id. ID is the key of the objects, and is assigned using a sequence.

Object subclass: #Parent
instanceVariableNames: 'top id'
 
Parent subclass: # LeftChild
instanceVariableNames: 'left referencedObject'
 
Parent subclass: #RightChild
instanceVariableNames: 'right referencedObject'


The information of this hierarchy's instances is persisted in the table ALL_DATA

And the important detail is that referencedObject is instance of ReferencedObject:

Object subclass: #ReferencedObject
instanceVariableNames: 'oneValue '

I configured this class to be persisted using an imaginary table (IMAGINARY_REFERENCED_OBJECT), and the mapping in the descriptors of both LeftChild and RightChild was specified using an EmbeddedValueOneToOneMapping.

With this configuration Glorp always fails when I try to bring all the elements of Parent (session read: Parent). The problem seems to be that in EmbeddedValueOneToOneMapping>>mapObject: anObject inElementBuilder: anElementBuilder, the framework tries to get the Builder for Base(Parent).referencedObject looking for it between the mappings of Parent. And when it does not find it, it ends up trying to send the message "instance" to nil.

I will next paste all of the SystemDescriptor configuration for you to see.

Thank your very much for your help,
Abel Armoa

_____________________________________________________________


allTableNames
^#('ALL_DATA' 'IMAGINARY_REFERENCED_OBJECT')
 
 
______________________________________________________________

classModelForLeftChild: aClassModel

aClassModel newAttributeNamed: #left.
aClassModel newAttributeNamed: #top.
aClassModel newAttributeNamed: #id.
aClassModel newAttributeNamed: #referencedObject type: ReferencedObject

______________________________________________________________

classModelForReferencedObject: aClassModel
   
   aClassModel newAttributeNamed: #oneValue.

_______________________________________________________________

classModelForRightChild: aClassModel

aClassModel newAttributeNamed: #right.
aClassModel newAttributeNamed: #top.
aClassModel newAttributeNamed: #id.
aClassModel newAttributeNamed: #referencedObject type: ReferencedObject

________________________________________________________________

constructAllClasses

^(super constructAllClasses)
add: Parent;
add: LeftChild;
add: RightChild;
add: ReferencedObject;
yourself

________________________________________________________________

descriptorForLeftChild: aDescriptor

| leftTable |

leftTable := self tableNamed: 'ALL_DATA'.
aDescriptor table: leftTable.
(aDescriptor newMapping: DirectMapping) from: #id to: (leftTable fieldNamed: 'id').
(aDescriptor newMapping: DirectMapping) from: #top to: (leftTable fieldNamed: 'top_value').
(aDescriptor newMapping: DirectMapping) from: #left to: (leftTable fieldNamed: 'left_value').
(aDescriptor newMapping: EmbeddedValueOneToOneMapping)
attributeName: #referencedObject;
fieldTranslation: (
(Join new)
addSource: (leftTable fieldNamed: 'referenced_object')
target:
((self tableNamed: 'IMAGINARY_REFERENCED_OBJECT') fieldNamed: 'one_value');
yourself).

(self typeResolverFor: Parent)
register: aDescriptor
keyedBy: 'L'
field: (leftTable fieldNamed: 'object_type')

___________________________________________________________________

descriptorForParent: aDescriptor

| table |

table := self tableNamed: 'ALL_DATA'.
aDescriptor table: table.
(aDescriptor newMapping: DirectMapping) from: #id to: (table fieldNamed: 'id').
(aDescriptor newMapping: DirectMapping) from: #top to: (table fieldNamed: 'top_value').
(self typeResolverFor: Parent) register: aDescriptor abstract: true

____________________________________________________________________

descriptorForReferencedObject: aDescriptor
 
   | table |
   table := self tableNamed: 'IMAGINARY_REFERENCED_OBJECT'.
   aDescriptor table: table.
   (aDescriptor newMapping: DirectMapping) from: #oneValue
 to: (table fieldNamed: 'one_value').

____________________________________________________________________

descriptorForRightChild: aDescriptor

| rightTable |

rightTable := self tableNamed: 'ALL_DATA'.
aDescriptor table: rightTable.
(aDescriptor newMapping: DirectMapping) from: #id to: (rightTable fieldNamed: 'id').
(aDescriptor newMapping: DirectMapping) from: #top to: (rightTable fieldNamed: 'top_value').
(aDescriptor newMapping: DirectMapping) from: #right to: (rightTable fieldNamed: 'right_value').
(aDescriptor newMapping: EmbeddedValueOneToOneMapping)
attributeName: #referencedObject;
fieldTranslation: (
(Join new)
addSource: (rightTable fieldNamed: 'referenced_object')
target:
((self tableNamed: 'IMAGINARY_REFERENCED_OBJECT') fieldNamed: 'one_value');
yourself).
(self typeResolverFor: Parent)
register: aDescriptor
keyedBy: 'R'
field: (rightTable fieldNamed: 'object_type')

______________________________________________________________________

tableForALL_DATA: aTable

(aTable createFieldNamed: 'top_value' type: (platform varChar: 50)).
(aTable createFieldNamed: 'left_value' type: (platform varChar: 50)).
(aTable createFieldNamed: 'right_value' type: (platform varChar: 50)).
(aTable createFieldNamed: 'object_type' type: (platform varChar: 2)).
(aTable createFieldNamed: 'id' type: (platform sequence)) bePrimaryKey.

(aTable createFieldNamed: 'referenced_object' type: (platform varChar: 50))

_______________________________________________________________________

tableForIMAGINARY_REFERENCED_OBJECT: aTable

aTable name: 'IMAGINARY_REFERENCED_OBJECT'.
aTable isImaginary: true.
(aTable createFieldNamed: 'one_value' type: (platform varChar: 50))

_______________________________________________________________________

Parent class>>#glorpTypeResolver

^FilteredTypeResolver forRootClass: Parent

 
 

--
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 [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.

--
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 [hidden email].
To post to this group, send email to [hidden email].
Visit this group at http://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.