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.
To do this, I created a base class, gave it the DiscriminatorColumn annotation, and then extended it with my various types. I do this simply to have strong types and to use the discriminator column to help me narrow the 5000+ entries down into more manageable lists.
Here are the classes:
Code:
@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:
Quote:
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:
Code:
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.
I'm not sure if this is a bug or not, but it seems to be somewhat odd behavior. It's entirely possible there's a better way to map these classes.
I'm open to any suggestions anyone may have.
---------------------------------------------
For the record, I'm using:
Hibernate Core: 3.2.6.ga
Hibernate EntityManager: 3.3.2.ga
Hibernate Annotations: 3.3.1.ga