HHH-4861 - Allow lookup by the "simple" pk type of "parent entity" in "derived identities" cases

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18686 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2010-02-03 06:58:46 +00:00
parent e2fc86d5d5
commit c86d471453
5 changed files with 155 additions and 51 deletions

View File

@ -14,55 +14,79 @@ public class DerivedIdentitySimpleParentSimpleDepTest extends TestCase {
public void testOneToOneExplicitJoinColumn() throws Exception { public void testOneToOneExplicitJoinColumn() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "MedicalHistory", "FK", getCfg() ) ); assertTrue( SchemaUtil.isColumnPresent( "MedicalHistory", "FK", getCfg() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "MedicalHistory", "id", getCfg() ) ); assertTrue( ! SchemaUtil.isColumnPresent( "MedicalHistory", "id", getCfg() ) );
Person e = new Person();
e.ssn = "aaa";
Session s = openSession(); Session s = openSession();
s.getTransaction().begin(); s.getTransaction().begin();
s.persist( e ); Person person = new Person( "aaa" );
MedicalHistory d = new MedicalHistory(); s.persist( person );
d.patient = e; MedicalHistory medicalHistory = new MedicalHistory( person );
s.persist( d ); s.persist( medicalHistory );
s.flush(); s.getTransaction().commit();
s.clear();
final Class<MedicalHistory> clazz = MedicalHistory.class;
d = getDerivedClassById( e, s, clazz );
assertEquals( e.ssn, d.patient.ssn );
d.lastupdate = new Date();
s.flush();
s.clear();
d = getDerivedClassById( e, s, clazz );
assertNotNull( d.lastupdate );
s.getTransaction().rollback();
s.close(); s.close();
}
private <T> T getDerivedClassById(Person e, Session s, Class<T> clazz) { s = openSession();
return ( T ) s.getTransaction().begin();
s.createQuery( "from " + clazz.getName() + " mh where mh.patient.ssn = :ssn") medicalHistory = (MedicalHistory) s.get( MedicalHistory.class, "aaa" );
.setParameter( "ssn", e.ssn ).uniqueResult(); assertEquals( person.ssn, medicalHistory.patient.ssn );
medicalHistory.lastupdate = new Date();
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
medicalHistory = (MedicalHistory) s.get( MedicalHistory.class, "aaa" );
assertNotNull( medicalHistory.lastupdate );
s.delete( medicalHistory );
s.getTransaction().commit();
s.close();
} }
public void testManyToOneExplicitJoinColumn() throws Exception { public void testManyToOneExplicitJoinColumn() throws Exception {
assertTrue( SchemaUtil.isColumnPresent( "FinancialHistory", "patient_ssn", getCfg() ) ); assertTrue( SchemaUtil.isColumnPresent( "FinancialHistory", "patient_ssn", getCfg() ) );
assertTrue( ! SchemaUtil.isColumnPresent( "FinancialHistory", "id", getCfg() ) ); assertTrue( ! SchemaUtil.isColumnPresent( "FinancialHistory", "id", getCfg() ) );
Person e = new Person();
e.ssn = "aaa";
Session s = openSession(); Session s = openSession();
s.getTransaction().begin(); s.getTransaction().begin();
Person person = new Person( "aaa" );
s.persist( person );
FinancialHistory financialHistory = new FinancialHistory( person );
s.persist( financialHistory );
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
financialHistory = (FinancialHistory) s.get( FinancialHistory.class, "aaa" );
assertEquals( person.ssn, financialHistory.patient.ssn );
financialHistory.lastUpdate = new Date();
s.getTransaction().commit();
s.close();
s = openSession();
s.getTransaction().begin();
financialHistory = (FinancialHistory) s.get( FinancialHistory.class, "aaa" );
assertNotNull( financialHistory.lastUpdate );
s.delete( financialHistory );
s.getTransaction().commit();
s.close();
}
public void testSimplePkValueLoading() {
Session s = openSession();
s.getTransaction().begin();
Person e = new Person( "aaa" );
s.persist( e ); s.persist( e );
FinancialHistory d = new FinancialHistory(); FinancialHistory d = new FinancialHistory( e );
d.patient = e;
s.persist( d ); s.persist( d );
s.flush(); s.getTransaction().commit();
s.clear(); s.close();
d = getDerivedClassById(e, s, FinancialHistory.class);
assertEquals( e.ssn, d.patient.ssn ); s = openSession();
d.lastupdate = new Date(); s.getTransaction().begin();
s.flush(); FinancialHistory history = (FinancialHistory) s.get( FinancialHistory.class, "aaa" );
s.clear(); assertNotNull( history );
d = getDerivedClassById(e, s, FinancialHistory.class); s.delete( history );
assertNotNull( d.lastupdate ); s.getTransaction().commit();
s.getTransaction().rollback();
s.close(); s.close();
} }

View File

@ -16,13 +16,18 @@ import javax.persistence.TemporalType;
*/ */
@Entity @Entity
public class FinancialHistory implements Serializable { public class FinancialHistory implements Serializable {
@Temporal(TemporalType.DATE)
Date lastupdate;
@Id @Id
//@JoinColumn(name = "FK") //@JoinColumn(name = "FK")
@ManyToOne @ManyToOne
Person patient; Person patient;
@Temporal(TemporalType.DATE)
Date lastUpdate;
public FinancialHistory() {
}
public FinancialHistory(Person patient) {
this.patient = patient;
}
} }

View File

@ -16,12 +16,18 @@ import javax.persistence.TemporalType;
*/ */
@Entity @Entity
public class MedicalHistory implements Serializable { public class MedicalHistory implements Serializable {
@Temporal(TemporalType.DATE)
Date lastupdate;
@Id @Id
@JoinColumn(name = "FK") @JoinColumn(name = "FK")
@OneToOne @OneToOne
Person patient; Person patient;
@Temporal(TemporalType.DATE)
Date lastupdate;
public MedicalHistory() {
}
public MedicalHistory(Person patient) {
this.patient = patient;
}
} }

View File

@ -11,4 +11,11 @@ import javax.persistence.Id;
public class Person { public class Person {
@Id @Id
String ssn; String ssn;
public Person() {
}
public Person(String ssn) {
this.ssn = ssn;
}
} }

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution * indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are * statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC. * distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,7 +20,6 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate.event.def; package org.hibernate.event.def;
@ -54,6 +53,8 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.EmbeddedComponentType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory; import org.hibernate.type.TypeFactory;
@ -106,6 +107,31 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
else { else {
Class idClass = persister.getIdentifierType().getReturnedClass(); Class idClass = persister.getIdentifierType().getReturnedClass();
if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) { if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) {
// we may have the kooky jpa requirement of allowing find-by-id where
// "id" is the "simple pk value" of a dependent objects parent. This
// is part of its generally goofy "derived identity" "feature"
if ( persister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
final EmbeddedComponentType dependentIdType =
(EmbeddedComponentType) persister.getEntityMetamodel().getIdentifierProperty().getType();
if ( dependentIdType.getSubtypes().length == 1 ) {
final Type singleSubType = dependentIdType.getSubtypes()[0];
if ( singleSubType.isEntityType() ) {
final EntityType dependentParentType = (EntityType) singleSubType;
final Type dependentParentIdType = dependentParentType.getIdentifierOrUniqueKeyType( source.getFactory() );
if ( dependentParentIdType.getReturnedClass().isInstance( event.getEntityId() ) ) {
// yep that's what we have...
loadByDerivedIdentitySimplePkValue(
event,
loadType,
persister,
dependentIdType,
source.getFactory().getEntityPersister( dependentParentType.getAssociatedEntityName() )
);
return;
}
}
}
}
throw new TypeMismatchException( throw new TypeMismatchException(
"Provided id of the wrong type for class " + persister.getEntityName() + ". Expected: " + idClass + ", got " + event.getEntityId().getClass() "Provided id of the wrong type for class " + persister.getEntityName() + ". Expected: " + idClass + ", got " + event.getEntityId().getClass()
); );
@ -136,6 +162,42 @@ public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener i
} }
} }
private void loadByDerivedIdentitySimplePkValue(
LoadEvent event,
LoadEventListener.LoadType options,
EntityPersister dependentPersister,
EmbeddedComponentType dependentIdType,
EntityPersister parentPersister) {
final EntityKey parentEntityKey = new EntityKey(
event.getEntityId(),
parentPersister,
event.getSession().getEntityMode()
);
final Object parent = doLoad(
event,
parentPersister,
parentEntityKey,
options
);
Serializable dependent = (Serializable) dependentIdType.instantiate( parent, event.getSession() );
dependentIdType.setPropertyValues( dependent, new Object[] {parent}, event.getSession().getEntityMode() );
final EntityKey dependentEntityKey = new EntityKey(
dependent,
dependentPersister,
event.getSession().getEntityMode()
);
event.setEntityId( dependent );
dependent = (Serializable) doLoad(
event,
dependentPersister,
dependentEntityKey,
options
);
event.setResult( dependent );
}
/** /**
* Perfoms the load of an entity. * Perfoms the load of an entity.
* *