-
1. Re: Support to joined inheritance strategy
adamw Sep 5, 2008 2:12 AM (in response to morman)Hello,
is the problem in generating the mapping in VersionsMetadataGenerator? I guess creating "dynamic" subclasses shold be possible - it works with @SecondaryTable (which creates a join - see the addJoins method) and single-table inheritance strategy (when reading a dynamically mapped "sub"-entity, the entity name is one of the elements of the map).
--
Adam -
2. Re: Support to joined inheritance strategy
morman Sep 5, 2008 3:28 AM (in response to morman)Hi Adam, thanks for your response ;).
The problem is with org.hibernate.persister.entity.AbstractEntityPersister. As far as i understand for entities involved in joined inheritance we need to use org.hibernate.persister.entity.JoinedSubclassEntityPersister, which extends AbstractEntityPersister. And the problem is in this abstract class's constructor in following piece of code:if ( persistentClass.hasPojoRepresentation() ) { //TODO: this is currently specific to pojos, but need to be available for all entity-modes Iterator iter = persistentClass.getSubclassIterator(); while ( iter.hasNext() ) { PersistentClass pc = ( PersistentClass ) iter.next(); entityNameBySubclass.put( pc.getMappedClass(), pc.getEntityName() ); } }
Problem is, that dynamicaly crreated entities (those with _versions suffix) has no pojo representation therefore hibernate is unable to map subclass entities.
The persistentClass.hasPojoRepresentation() is quite simple it just looking if given persistentClass has className property set. In current implementation this property is always null and I was unable to find place where this class is being populated and where I can set this property. Could you point me appropriate place? ;).
Nevertheless the problem is that hibernate will try to load class with this name, and no classes with "_versions" suffix are possible to load. It needs it to map the subclass entities.
Hope you understand my point :).
Currently I am experimenting with dynamic class compilation using BCEL.
Michal -
3. Re: Support to joined inheritance strategy
adamw Sep 5, 2008 10:54 AM (in response to morman)Ah, I see. Hmm, well, there must be a reason the persister has this flag :) Though, you can try compiling hibernate with this turned off and see what happens :) Maybe it's also possible to create a subclass of this persister, overriding the method that has this check?
The mappings for the dynamic entities are generated in VersionsMetadataGenerator.
With BCEL - you want to create subclasses of the entities with the additonal fields added, and then map this class, instead of using dynamic entities? I thought about that initially too, but then decided that using dynamic entities will be easier. However it has its drawbacks. For example, when mapping a relation, you can't leave it as a one-to-many relation, you have to map the ID properties directly.
--
Adam -
4. Re: Support to joined inheritance strategy
morman Sep 10, 2008 4:44 AM (in response to morman)I've added dynamically compiled class for every classes that are annotated with @Versioned and also set the className property for PersistentClasses in configuration, but it still not work :). Now I've got the exception:
Caused by: org.hibernate.PropertyNotFoundException: Could not find a getter for originalId in class com.consileon.reportingtool.data.dataobjects.InvoiceInput_versions at org.hibernate.property.BasicPropertyAccessor.createGetter(BasicPropertyAccessor.java:282) at org.hibernate.property.BasicPropertyAccessor.getGetter(BasicPropertyAccessor.java:275) at org.hibernate.tuple.PropertyFactory.getGetter(PropertyFactory.java:168) at org.hibernate.tuple.PropertyFactory.buildIdentifierProperty(PropertyFactory.java:44) at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:124) at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:434) at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:109) at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:55) at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:226) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1300) at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:814) at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:732) at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:211) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334) ... 78 more
The funniest thing is that property 'orginalId' doesn't exist in whole InvoiceInput class hierarchy, so I cannot simply copy InvoiceInput classes properties to InvoiceInvput_versions.
Have any idea where this property comes from? Is envers adds this property to mapping/configuration in some step? -
5. Re: Support to joined inheritance strategy
adamw Sep 12, 2008 2:26 AM (in response to morman)Hello,
wow! So now the mappings are to real classes, dynamically generated? Nice :).
The originalId property is the primary key for the versions class. It consists of fields that constituted the original id of the entity plus the revision number.
If you go to org.jboss.envers.configuration.EntitiesConfigurator and uncomment the "writeDocument" invocations, you'll see exactly how things are mapped (when you run your application).
Adam -
6. Re: Support to joined inheritance strategy
morman Sep 16, 2008 7:29 AM (in response to morman)While I have some problems with generating methods with BCEL I've done a little workaround and write *_versions classes by hand. I've copied all properties from the orginal classes and add: orginalId, _revision and _revision_type (together with appropriate setters and getters). And guess what... it still not works :).
Currently I've got problem with getSubclassEntityPersister method in AbstractEntityPersister where I've got the following exception:org.hibernate.HibernateException: instance not of expected entity type: java.util.HashMap is not a: com.consileon.reportingtool.data.dataobjects.Company_versions at org.hibernate.persister.entity.AbstractEntityPersister.getSubclassEntityPersister(AbstractEntityPersister.java:3640) at org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1347) at org.hibernate.id.Assigned.generate(Assigned.java:28) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:99) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187) at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172) at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70) at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523) at org.jboss.envers.synchronization.work.ModWorkUnit.perform(ModWorkUnit.java:56) at org.jboss.envers.synchronization.VersionsSync.executeInSession(VersionsSync.java:120) ...(cut)
What can be observed is that hibernate expecting 'instance' to be set to versioned class, instead of this we have HashMap. As I investigated this map is set in ModWorkUnit. Could you explain me what is the purpose of this class and why HashMap is used?
As I understand, this map contains properties for all versioned entities. Map is used beacuse there was no real classes for *_versions entities, and now if I dynamically create those classes I can made appropriate instances, set appropriate properties and use this object instead of HashMap. Am I right? -
7. Re: Support to joined inheritance strategy
morman Sep 18, 2008 3:10 AM (in response to morman)I've done a little more investigation regarding this issue, and I think that if Hibernate has ability to map objects as Map of properties, than it must exist a way to map joined inheritance as such Map. Perhaps there is no need to have concrete classes, and just do appropriate mapping (maybe a Map of Maps ;)). Perhaps some other persister is required to be used instead of JoinedSubclassEntityPersister.
This approach should be easier to implement. Have any clues how to map joined inheritence using Map's in Hibernate? -
8. Re: Support to joined inheritance strategy
adamw Sep 19, 2008 2:16 AM (in response to morman)Hello,
regarding your last but one post: you are right. The ModWorkUnit, similarly to other work units, just maps the entity state to a map, using a property mapper (which has a method for that). The property mapper stores informatino about an entities' properties, reads them from the bean and writes to a map.
As to your second post, well, maybe it would be good first to try implementing joined-inhertiance persistence for dynamic models. So, create a dynamic model, a custom persister (the code of the persister could be copied from the original one, but with the problematic "if" removed) and see if it works :).
--
Adam -
9. Re: Support to joined inheritance strategy
morman Sep 19, 2008 4:25 AM (in response to morman)Well it not so simple to remove the problematic if, while it is in constructor of AbstractEntityPersister so it is not possible to do simple inheritance, but copy-paste the code and rewrite the constructor ;). And the problem is if hibernate represent entity subclasses using Class to entity name map then it is highly possible that in some place it will try to read this mapping and then it will not find suitable class ;).
I've added to my dynamic class compilation model such behaviour that instead of persisting entities represented by maps i use the instances of classes that i create dynamically. And new exception occurs:java.lang.ClassCastException: com.consileon.reportingtool.data.dataobjects.Branch_versions cannot be cast to java.util.Map (...)
In my application Branch is extending Company (wich was present in my previous posts :)). So it seems that if I use maps the Company_versions causes the exception (superclass) and if I use real instances the Branch_versions causes the eception (subclass) :).
I think that the best solution will be to find out if it is possible (and how) to represent joined-inheritance in Hibernate using map of properties representation. Otherwise it seems that lot of changes will be required to be done (including writing custom persister from scratch ;)). -
10. Re: Support to joined inheritance strategy
adamw Sep 19, 2008 5:47 AM (in response to morman)Hello,
maybe try the hibernate forum? And copying the abstract entities perister constructor :).
When using dynamic models with inheritance, the type of the entity is stored in a special field: $type$. Also, the single-table strategy works with dynamic models.
--
Adam