[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-3445) Single Table Inheritence Broken for non table-unique keys

Todd Tidwell (JIRA) noreply at atlassian.com
Mon Jun 15 21:03:33 EDT 2009


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-3445?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=33412#action_33412 ] 

Todd Tidwell commented on HHH-3445:
-----------------------------------

I never did get any feedback or traction.

I found that the real problem is this:  You're using single-table inheritance, basically, and the way it's coded in Hibernate doesn't take into account that the primary key needs to be both the discriminator value *and* the unique identifier.  So, what happens in the existing code is that all items from a single table get treated as the root-level object in the inheritance path.  My solution was to finally create many, many views for each discriminator value and simply map them separately.  

This worked for me because I didn't ever need to update these objects.  However, if anyone ever wants to use this for legacy applications that work like what we've encountered, this will have to be patched as I recommended (and tested successfully).


> Single Table Inheritence Broken for non table-unique keys
> ---------------------------------------------------------
>
>                 Key: HHH-3445
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-3445
>             Project: Hibernate Core
>          Issue Type: Bug
>         Environment: Hibernate Core: 3.2.6.ga
> Hibernate Annotations: 3.3.1.ga
> Hibernate EntityManager: 3.3.2.ga
> DB2 Linux 9.1
>            Reporter: Todd Tidwell
>         Attachments: entity-key-patch.patch
>
>
> I have an interesting mapping case that is causing me some very odd low-level errors. In this particular case, I'm working with a table that contains multiple objects and I can use a DiscriminatorColumn to differentiate.   However, the "primary key" for the child objects is not guaranteed to be uniqe table-wide.  For example, DiscriminatorColumn value '013' may have a unique-key value of 'A', DiscriminatorColumn '014' may have the same unique-key value.
> To map this, I created a base class, gave it the DiscriminatorColumn annotation, and then extended it with my various types.
> Here are the classes: 
> @Entity 
> @Table(name="WTTBLE") 
> @DiscriminatorColumn(name="PTBLE") 
> public abstract class MetaData 
> { 
>   @Id 
>   @Basic(fetch=FetchType.EAGER) 
>   @Column(name="PCODE", nullable=false, insertable=false, updatable=false) 
>   private String code = null; 
>   
>   @Basic(fetch=FetchType.EAGER) 
>   @Column(name="DEF", nullable=false, insertable=false, updatable=false) 
>   private String value = null; 
>   
>   .... 
> } 
> @Entity 
> @DiscriminatorValue(value = "015") 
> public class AddressType 
> extends MetaData 
> { 
>    // No fields here, they're all mapped in MetaData 
> } 
> @Entity 
> @DiscriminatorValue(value = "016") 
> public class CustomerType 
> extends MetaData 
> { 
>    // No fields here, they're all mapped in MetaData 
> } 
>  
> Now, this works great until they both have the same value for the "code" property. At that point, I get the following logging and exception: 
> org.hibernate.impl.SessionImpl - initializing proxy: [com.wiley.permissions.domain.persistence.wintouch.metadata.AddressType#A] 
> .... 
> org.hibernate.event.def.DefaultLoadEventListener - load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null 
> .... 
> javax.persistence.EntityNotFoundException: Unable to find test.AddressType with id A 
> at org.hibernate.ejb.Ejb3Configuration$Ejb3EntityNotFoundDelegate.handleEntityNotFound(Ejb3Configuration.java:107) 
> at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:79) 
> at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:68) 
> at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111) 
> at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150) 
> at test.AddressType$$EnhancerByCGLIB$$16d4c983.getValue(<generated>) 
>  
> After some serious research, I found that org.hibernate.engine.StatefulPersistenceContext is returning the wrong object from it's getEntity method. It's returning a CustomerType object, which was added to the session's cache after the address type. On furthur examination, this seems to be because org.hibernate.engine.EntityKey.equals() is returning the same value for both objects. EntityKey's code for lines 95 -99 is: 
> public boolean equals(Object other) { 
>    EntityKey otherKey = (EntityKey) other; 
>    return otherKey.rootEntityName.equals(this.rootEntityName) && 
>    identifierType.isEqual(otherKey.identifier, this.identifier, entityMode, factory); 
> } 
>  
> Examination of the values of EntityKey for my objects show that rootEntityName for both objects is test.MetaData. That means that this method is going to return true. That, in turn, means that StatefulPersistenceContext's entitiesByKey HashMap is going to return the first one that equals the one passed into the get() method. 

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the hibernate-issues mailing list