[hibernate-commits] Hibernate SVN: r10776 - in branches/Branch_3_2/Hibernate3: src/org/hibernate/type test/org/hibernate/test/ops
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Wed Nov 8 17:02:13 EST 2006
Author: steve.ebersole at jboss.com
Date: 2006-11-08 17:02:07 -0500 (Wed, 08 Nov 2006)
New Revision: 10776
Added:
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Address.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/OneToOne.hbm.xml
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Person.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/PersonalDetails.java
Modified:
branches/Branch_3_2/Hibernate3/src/org/hibernate/type/EntityType.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/AbstractOperationTestCase.java
branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/MergeTest.java
Log:
HHH-2138 : merge and bidirectional one-to-one
Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/type/EntityType.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/type/EntityType.java 2006-11-08 16:56:52 UTC (rev 10775)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/type/EntityType.java 2006-11-08 22:02:07 UTC (rev 10776)
@@ -27,7 +27,8 @@
import org.hibernate.util.ReflectHelper;
/**
- * A reference to an entity class
+ * Base for types which map associations to persistent entities.
+ *
* @author Gavin King
*/
public abstract class EntityType extends AbstractType implements AssociationType {
@@ -37,38 +38,27 @@
protected final boolean isEmbeddedInXML;
private final boolean eager;
private final boolean unwrapProxy;
-
- public boolean isEmbeddedInXML() {
- return isEmbeddedInXML;
- }
-
- public final boolean isEntityType() {
- return true;
- }
-
- public String getPropertyName() {
- return null;
- }
- public final String getAssociatedEntityName() {
- return associatedEntityName;
- }
+ private transient Class returnedClass;
- public final boolean isSame(Object x, Object y, EntityMode entityMode) {
- return x==y;
- }
-
- public int compare(Object x, Object y, EntityMode entityMode) {
- return 0; //TODO: entities CAN be compared, by PK, fix this!
- }
-
+ /**
+ * Constructs the requested entity type mapping.
+ *
+ * @param entityName The name of the associated entity.
+ * @param uniqueKeyPropertyName The property-ref name, or null if we
+ * reference the PK of the associated entity.
+ * @param eager Is eager fetching enabled.
+ * @param isEmbeddedInXML Should values of this mapping be embedded in XML modes?
+ * @param unwrapProxy Is unwrapping of proxies allowed for this association; unwrapping
+ * says to return the "implementation target" of lazy prooxies; typically only possible
+ * with lazy="no-proxy".
+ */
protected EntityType(
- String entityName,
- String uniqueKeyPropertyName,
- boolean eager,
+ String entityName,
+ String uniqueKeyPropertyName,
+ boolean eager,
boolean isEmbeddedInXML,
- boolean unwrapProxy
- ) {
+ boolean unwrapProxy) {
this.associatedEntityName = entityName;
this.uniqueKeyPropertyName = uniqueKeyPropertyName;
this.isEmbeddedInXML = isEmbeddedInXML;
@@ -76,322 +66,209 @@
this.unwrapProxy = unwrapProxy;
}
- public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
- throws HibernateException, SQLException {
- return nullSafeGet( rs, new String[] {name}, session, owner );
+ /**
+ * An entity type is a type of association type
+ *
+ * @return True.
+ */
+ public boolean isAssociationType() {
+ return true;
}
/**
- * This returns the wrong class for an entity with a proxy, or for
- * a named entity. Theoretically it should return the proxy class,
- * but it doesn't.
+ * Explicitly, an entity type is an entity type ;)
+ *
+ * @return True.
*/
- public final Class getReturnedClass() {
- try {
- return ReflectHelper.classForName(associatedEntityName);
- }
- catch (ClassNotFoundException cnfe) {
- return java.util.Map.class;
- }
+ public final boolean isEntityType() {
+ return true;
}
- /*protected final Object getActualIdentifier(Object value, SessionImplementor session) throws HibernateException {
- return session.getEntityIdentifierIfNotUnsaved(value); //tolerates nulls
- }*/
-
- protected final Object getIdentifier(Object value, SessionImplementor session)
- throws HibernateException {
-
- if ( isNotEmbedded(session) ) return value;
-
- if ( isReferenceToPrimaryKey() ) {
- return ForeignKeys.getEntityIdentifierIfNotUnsaved(associatedEntityName, value, session); //tolerates nulls
- }
- else if (value==null) {
- return null;
- }
- else {
- return session.getFactory()
- .getEntityPersister( getAssociatedEntityName() )
- .getPropertyValue( value, uniqueKeyPropertyName, session.getEntityMode() );
- }
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isMutable() {
+ return false;
}
- protected boolean isNotEmbedded(SessionImplementor session) {
- return !isEmbeddedInXML && session.getEntityMode()==EntityMode.DOM4J;
+ /**
+ * Generates a string representation of this type.
+ *
+ * @return string rep
+ */
+ public String toString() {
+ return getClass().getName() + '(' + getAssociatedEntityName() + ')';
}
/**
- * Get the identifier value of an instance or proxy
+ * For entity types, the name correlates to the associated entity name.
*/
- private static Serializable getIdentifier(Object object, EntityPersister persister, EntityMode entityMode)
- throws HibernateException {
- if (object instanceof HibernateProxy) {
- HibernateProxy proxy = (HibernateProxy) object;
- LazyInitializer li = proxy.getHibernateLazyInitializer();
- return li.getIdentifier();
- }
- else {
- return persister.getIdentifier( object, entityMode );
- }
- }
-
- public String toLoggableString(Object value, SessionFactoryImplementor factory)
- throws HibernateException {
-
- if (value==null) return "null";
-
- EntityPersister persister = factory.getEntityPersister(associatedEntityName);
- StringBuffer result = new StringBuffer()
- .append(associatedEntityName);
-
- if ( persister.hasIdentifierProperty() ) {
- //TODO: use of a guess here is bad...
- final EntityMode entityMode = persister.guessEntityMode(value);
- final Serializable id;
- if (entityMode==null) {
- if ( isEmbeddedInXML ) {
- throw new ClassCastException( value.getClass().getName() );
- }
- id = (Serializable) value;
- }
- else {
- id = getIdentifier( value, persister, entityMode );
- }
-
- result.append('#')
- .append( persister.getIdentifierType().toLoggableString(id, factory) );
- }
-
- return result.toString();
+ public String getName() {
+ return associatedEntityName;
}
-
- /*public String toXMLString(Object value, SessionFactoryImplementor factory) throws HibernateException {
- if (isEmbeddedInXML) throw new UnsupportedOperationException("entity references cannot be stringified");
- if (factory==null) throw new AssertionFailure("null factory passed to toString");
- return getIdentifierType(factory).toXMLString(value, factory);
- }
- public Object fromXMLString(String xml, Mapping factory) throws HibernateException {
- if (isEmbeddedInXML) throw new UnsupportedOperationException("entity references cannot be stringified");
- if (factory==null) throw new AssertionFailure("null factory passed to fromString");
- return getIdentifierType(factory).fromXMLString(xml, factory);
- }*/
-
- public String getName() { return associatedEntityName; }
-
- public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) {
- return value; //special case ... this is the leaf of the containment graph, even though not immutable
+ /**
+ * Does this association foreign key reference the primary key of the other table?
+ * Otherwise, it references a property-ref.
+ *
+ * @return True if this association reference the PK of the associated entity.
+ */
+ public boolean isReferenceToPrimaryKey() {
+ return uniqueKeyPropertyName==null;
}
- public boolean isMutable() {
- return false;
+ public String getRHSUniqueKeyPropertyName() {
+ return uniqueKeyPropertyName;
}
- public abstract boolean isOneToOne();
-
- public Object replace(Object original, Object target, SessionImplementor session, Object owner, Map copyCache)
- throws HibernateException {
- if (original==null) return null;
- Object cached = copyCache.get(original);
- if (cached!=null) {
- return cached;
- }
- else {
- if (original==target) return target;
- //TODO: can this ever get called????
- Object id = getIdentifier(original, session);
- if (id==null) throw new AssertionFailure("cannot copy a reference to an object with a null id");
- id = getIdentifierOrUniqueKeyType( session.getFactory() )
- .replace(id, null, session, owner, copyCache);
- return resolve(id, session, owner);
- }
+ public String getLHSPropertyName() {
+ return null;
}
- public boolean isAssociationType() {
- return true;
+ public String getPropertyName() {
+ return null;
}
- public final Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner)
- throws HibernateException, SQLException {
- return resolve( hydrate(rs, names, session, owner), session, owner );
+ /**
+ * The name of the associated entity.
+ *
+ * @return The associated entity name.
+ */
+ public final String getAssociatedEntityName() {
+ return associatedEntityName;
}
- public Joinable getAssociatedJoinable(SessionFactoryImplementor factory)
- throws MappingException {
- return (Joinable) factory.getEntityPersister(associatedEntityName);
+ /**
+ * The name of the associated entity.
+ *
+ * @param factory The session factory, for resolution.
+ * @return The associated entity name.
+ */
+ public String getAssociatedEntityName(SessionFactoryImplementor factory) {
+ return getAssociatedEntityName();
}
-
- Type getIdentifierType(Mapping factory) {
- return factory.getIdentifierType( getAssociatedEntityName() );
- }
- Type getIdentifierType(SessionImplementor session) throws MappingException {
- return getIdentifierType( session.getFactory() );
+ /**
+ * Retrieves the {@link Joinable} defining the associated entity.
+ *
+ * @param factory The session factory.
+ * @return The associated joinable
+ * @throws MappingException Generally indicates an invalid entity name.
+ */
+ public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) throws MappingException {
+ return ( Joinable ) factory.getEntityPersister( associatedEntityName );
}
- public final Type getIdentifierOrUniqueKeyType(Mapping factory)
- throws MappingException {
- if ( isReferenceToPrimaryKey() ) {
- return getIdentifierType(factory);
+ /**
+ * This returns the wrong class for an entity with a proxy, or for a named
+ * entity. Theoretically it should return the proxy class, but it doesn't.
+ * <p/>
+ * The problem here is that we do not necessarily have a ref to the associated
+ * entity persister (nor to the session factory, to look it up) which is really
+ * needed to "do the right thing" here...
+ *
+ * @return The entiyt class.
+ */
+ public final Class getReturnedClass() {
+ if ( returnedClass == null ) {
+ returnedClass = determineAssociatedEntityClass();
}
- else {
- return factory.getReferencedPropertyType( getAssociatedEntityName(), uniqueKeyPropertyName );
- }
+ return returnedClass;
}
- public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory)
- throws MappingException {
- if ( isReferenceToPrimaryKey() ) {
- return factory.getIdentifierPropertyName( getAssociatedEntityName() );
+ private Class determineAssociatedEntityClass() {
+ try {
+ return ReflectHelper.classForName( getAssociatedEntityName() );
}
- else {
- return uniqueKeyPropertyName;
+ catch ( ClassNotFoundException cnfe ) {
+ return java.util.Map.class;
}
}
-
- protected abstract boolean isNullable();
/**
- * Resolve an identifier
+ * {@inheritDoc}
*/
- protected final Object resolveIdentifier(Serializable id, SessionImplementor session)
- throws HibernateException {
-
- boolean isProxyUnwrapEnabled = unwrapProxy &&
- session.getFactory()
- .getEntityPersister( getAssociatedEntityName() )
- .isInstrumented( session.getEntityMode() );
-
- Object proxyOrEntity = session.internalLoad(
- getAssociatedEntityName(),
- id,
- eager,
- isNullable() && !isProxyUnwrapEnabled
- );
-
- if (proxyOrEntity instanceof HibernateProxy) {
- ( (HibernateProxy) proxyOrEntity ).getHibernateLazyInitializer()
- .setUnwrap(isProxyUnwrapEnabled);
- }
-
- return proxyOrEntity;
+ public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
+ throws HibernateException, SQLException {
+ return nullSafeGet( rs, new String[] {name}, session, owner );
}
- protected boolean isNull(Object owner, SessionImplementor session) {
- return false;
- }
-
/**
- * Resolve an identifier or unique key value
+ * {@inheritDoc}
*/
- public Object resolve(Object value, SessionImplementor session, Object owner)
- throws HibernateException {
-
- if ( isNotEmbedded(session) ) {
- return value;
- }
-
- if (value==null) {
- return null;
- }
- else {
-
- if ( isNull(owner, session) ) return null; //EARLY EXIT!
-
- if ( isReferenceToPrimaryKey() ) {
- return resolveIdentifier( (Serializable) value, session );
- }
- else {
- return loadByUniqueKey(
- getAssociatedEntityName(),
- uniqueKeyPropertyName,
- value,
- session
- );
- }
- }
+ public final Object nullSafeGet(
+ ResultSet rs,
+ String[] names,
+ SessionImplementor session,
+ Object owner) throws HibernateException, SQLException {
+ return resolve( hydrate(rs, names, session, owner), session, owner );
}
- public String getAssociatedEntityName(SessionFactoryImplementor factory) {
- return getAssociatedEntityName();
+ /**
+ * Two entities are considered the same when their instances are the same.
+ *
+ * @param x One entity instance
+ * @param y Another entity instance
+ * @param entityMode The entity mode.
+ * @return True if x == y; false otherwise.
+ */
+ public final boolean isSame(Object x, Object y, EntityMode entityMode) {
+ return x == y;
}
/**
- * Does this association foreign key reference the
- * primary key of the other table?
+ * {@inheritDoc}
*/
- public boolean isReferenceToPrimaryKey() {
- return uniqueKeyPropertyName==null;
+ public int compare(Object x, Object y, EntityMode entityMode) {
+ return 0; //TODO: entities CAN be compared, by PK, fix this! -> only if/when we can extract the id values....
}
-
- public String getRHSUniqueKeyPropertyName() {
- return uniqueKeyPropertyName;
- }
- public String toString() {
- return getClass().getName() + '(' + getAssociatedEntityName() + ')';
+ /**
+ * {@inheritDoc}
+ */
+ public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory) {
+ return value; //special case ... this is the leaf of the containment graph, even though not immutable
}
/**
- * Load an instance by a unique key that is not the primary key.
+ * {@inheritDoc}
*/
- public Object loadByUniqueKey(
- String entityName,
- String uniqueKeyPropertyName,
- Object key,
- SessionImplementor session)
- throws HibernateException {
-
- final SessionFactoryImplementor factory = session.getFactory();
-
- UniqueKeyLoadable persister = (UniqueKeyLoadable) factory.getEntityPersister(entityName);
-
- //TODO: implement caching?! proxies?!
-
- EntityUniqueKey euk = new EntityUniqueKey(
- entityName,
- uniqueKeyPropertyName,
- key,
- getIdentifierOrUniqueKeyType( factory ),
- session.getEntityMode(),
- session.getFactory()
- );
-
- final PersistenceContext persistenceContext = session.getPersistenceContext();
- Object result = persistenceContext.getEntity(euk);
- //if ( result==null && !persistenceContext.isNonExistant(euk) ) {
- if ( result==null ) {
- result = persister.loadByUniqueKey(uniqueKeyPropertyName, key, session);
+ public Object replace(
+ Object original,
+ Object target,
+ SessionImplementor session,
+ Object owner,
+ Map copyCache) throws HibernateException {
+ if ( original == null ) {
+ return null;
}
- return result==null ? null : persistenceContext.proxyFor(result);
-
- }
-
- public String getLHSPropertyName() {
- return null;
- }
-
- public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters)
- throws MappingException {
- if ( isReferenceToPrimaryKey() ) { //TODO: this is a bit arbitrary, expose a switch to the user?
- return "";
+ Object cached = copyCache.get(original);
+ if ( cached != null ) {
+ return cached;
}
else {
- return getAssociatedJoinable(factory).filterFragment(alias, enabledFilters);
+ if ( original == target ) {
+ return target;
+ }
+ Object id = getIdentifier( original, session );
+ if ( id == null ) {
+ throw new AssertionFailure("cannot copy a reference to an object with a null id");
+ }
+ id = getIdentifierOrUniqueKeyType( session.getFactory() )
+ .replace(id, null, session, owner, copyCache);
+ return resolve( id, session, owner );
}
}
-
- public Type getSemiResolvedType(SessionFactoryImplementor factory) {
- return factory.getEntityPersister(associatedEntityName).getIdentifierType();
- }
-
+
+ /**
+ * {@inheritDoc}
+ */
public int getHashCode(Object x, EntityMode entityMode, SessionFactoryImplementor factory) {
EntityPersister persister = factory.getEntityPersister(associatedEntityName);
if ( !persister.canExtractIdOutOfEntity() ) {
return super.getHashCode(x, entityMode);
}
-
+
final Serializable id;
if (x instanceof HibernateProxy) {
id = ( (HibernateProxy) x ).getHibernateLazyInitializer().getIdentifier();
@@ -401,13 +278,16 @@
}
return persister.getIdentifierType().getHashCode(id, entityMode, factory);
}
-
+
+ /**
+ * {@inheritDoc}
+ */
public boolean isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory) {
EntityPersister persister = factory.getEntityPersister(associatedEntityName);
if ( !persister.canExtractIdOutOfEntity() ) {
return super.isEqual(x, y, entityMode);
}
-
+
Serializable xid;
if (x instanceof HibernateProxy) {
xid = ( (HibernateProxy) x ).getHibernateLazyInitializer()
@@ -416,7 +296,7 @@
else {
xid = persister.getIdentifier(x, entityMode);
}
-
+
Serializable yid;
if (y instanceof HibernateProxy) {
yid = ( (HibernateProxy) y ).getHibernateLazyInitializer()
@@ -425,15 +305,28 @@
else {
yid = persister.getIdentifier(y, entityMode);
}
-
+
return persister.getIdentifierType()
.isEqual(xid, yid, entityMode, factory);
}
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmbeddedInXML() {
+ return isEmbeddedInXML;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
public boolean isXMLElement() {
return isEmbeddedInXML;
}
+ /**
+ * {@inheritDoc}
+ */
public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
if ( !isEmbeddedInXML ) {
return getIdentifierType(factory).fromXMLNode(xml, factory);
@@ -443,8 +336,10 @@
}
}
- public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory)
- throws HibernateException {
+ /**
+ * {@inheritDoc}
+ */
+ public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException {
if ( !isEmbeddedInXML ) {
getIdentifierType(factory).setToXMLNode(node, value, factory);
}
@@ -454,4 +349,265 @@
}
}
+ public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters)
+ throws MappingException {
+ if ( isReferenceToPrimaryKey() ) { //TODO: this is a bit arbitrary, expose a switch to the user?
+ return "";
+ }
+ else {
+ return getAssociatedJoinable( factory ).filterFragment( alias, enabledFilters );
+ }
+ }
+
+ /**
+ * Resolve an identifier or unique key value
+ */
+ public Object resolve(Object value, SessionImplementor session, Object owner) throws HibernateException {
+ if ( isNotEmbedded( session ) ) {
+ return value;
+ }
+
+ if ( value == null ) {
+ return null;
+ }
+ else {
+ if ( isNull( owner, session ) ) {
+ return null; //EARLY EXIT!
+ }
+
+ if ( isReferenceToPrimaryKey() ) {
+ return resolveIdentifier( (Serializable) value, session );
+ }
+ else {
+ return loadByUniqueKey( getAssociatedEntityName(), uniqueKeyPropertyName, value, session );
+ }
+ }
+ }
+
+ public Type getSemiResolvedType(SessionFactoryImplementor factory) {
+ return factory.getEntityPersister( associatedEntityName ).getIdentifierType();
+ }
+
+ protected final Object getIdentifier(Object value, SessionImplementor session) throws HibernateException {
+ if ( isNotEmbedded(session) ) {
+ return value;
+ }
+
+ if ( isReferenceToPrimaryKey() ) {
+ return ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); //tolerates nulls
+ }
+ else if ( value == null ) {
+ return null;
+ }
+ else {
+ EntityPersister entityPersister = session.getFactory().getEntityPersister( getAssociatedEntityName() );
+ Object propertyValue = entityPersister.getPropertyValue( value, uniqueKeyPropertyName, session.getEntityMode() );
+ // We now have the value of the property-ref we reference. However,
+ // we need to dig a little deeper, as that property might also be
+ // an entity type, in which case we need to resolve its identitifier
+ Type type = entityPersister.getPropertyType( uniqueKeyPropertyName );
+ if ( type.isEntityType() ) {
+ propertyValue = ( ( EntityType ) type ).getIdentifier( propertyValue, session );
+ }
+
+ return propertyValue;
+ }
+ }
+
+ protected boolean isNotEmbedded(SessionImplementor session) {
+ return !isEmbeddedInXML && session.getEntityMode()==EntityMode.DOM4J;
+ }
+
+ /**
+ * Get the identifier value of an instance or proxy.
+ * <p/>
+ * Intended only for loggin purposes!!!
+ *
+ * @param object The object from which to extract the identifier.
+ * @param persister The entity persister
+ * @param entityMode The entity mode
+ * @return The extracted identifier.
+ */
+ private static Serializable getIdentifier(Object object, EntityPersister persister, EntityMode entityMode) {
+ if (object instanceof HibernateProxy) {
+ HibernateProxy proxy = (HibernateProxy) object;
+ LazyInitializer li = proxy.getHibernateLazyInitializer();
+ return li.getIdentifier();
+ }
+ else {
+ return persister.getIdentifier( object, entityMode );
+ }
+ }
+
+ /**
+ * Generate a loggable representation of an instance of the value mapped by this type.
+ *
+ * @param value The instance to be logged.
+ * @param factory The session factory.
+ * @return The loggable string.
+ * @throws HibernateException Generally some form of resolution problem.
+ */
+ public String toLoggableString(Object value, SessionFactoryImplementor factory) {
+ if ( value == null ) {
+ return "null";
+ }
+
+ EntityPersister persister = factory.getEntityPersister( associatedEntityName );
+ StringBuffer result = new StringBuffer().append( associatedEntityName );
+
+ if ( persister.hasIdentifierProperty() ) {
+ final EntityMode entityMode = persister.guessEntityMode( value );
+ final Serializable id;
+ if ( entityMode == null ) {
+ if ( isEmbeddedInXML ) {
+ throw new ClassCastException( value.getClass().getName() );
+ }
+ id = ( Serializable ) value;
+ }
+ else {
+ id = getIdentifier( value, persister, entityMode );
+ }
+
+ result.append( '#' )
+ .append( persister.getIdentifierType().toLoggableString( id, factory ) );
+ }
+
+ return result.toString();
+ }
+
+ public abstract boolean isOneToOne();
+
+ /**
+ * Convenience method to locate the identifier type of the associated entity.
+ *
+ * @param factory The mappings...
+ * @return The identifier type
+ */
+ Type getIdentifierType(Mapping factory) {
+ return factory.getIdentifierType( getAssociatedEntityName() );
+ }
+
+ /**
+ * Convenience method to locate the identifier type of the associated entity.
+ *
+ * @param session The originating session
+ * @return The identifier type
+ */
+ Type getIdentifierType(SessionImplementor session) {
+ return getIdentifierType( session.getFactory() );
+ }
+
+ /**
+ * Determine the type of either (1) the identifier if we reference the
+ * associated entity's PK or (2) the unique key to which we refer (i.e.
+ * the property-ref).
+ *
+ * @param factory The mappings...
+ * @return The appropriate type.
+ * @throws MappingException Generally, if unable to resolve the associated entity name
+ * or unique key property name.
+ */
+ public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException {
+ if ( isReferenceToPrimaryKey() ) {
+ return getIdentifierType(factory);
+ }
+ else {
+ Type type = factory.getReferencedPropertyType( getAssociatedEntityName(), uniqueKeyPropertyName );
+ if ( type.isEntityType() ) {
+ type = ( ( EntityType ) type).getIdentifierOrUniqueKeyType( factory );
+ }
+ return type;
+ }
+ }
+
+ /**
+ * The name of the property on the associated entity to which our FK
+ * refers
+ *
+ * @param factory The mappings...
+ * @return The appropriate property name.
+ * @throws MappingException Generally, if unable to resolve the associated entity name
+ */
+ public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory)
+ throws MappingException {
+ if ( isReferenceToPrimaryKey() ) {
+ return factory.getIdentifierPropertyName( getAssociatedEntityName() );
+ }
+ else {
+ return uniqueKeyPropertyName;
+ }
+ }
+
+ protected abstract boolean isNullable();
+
+ /**
+ * Resolve an identifier via a load.
+ *
+ * @param id The entity id to resolve
+ * @param session The orginating session.
+ * @return The resolved identifier (i.e., loaded entity).
+ * @throws org.hibernate.HibernateException Indicates problems performing the load.
+ */
+ protected final Object resolveIdentifier(Serializable id, SessionImplementor session) throws HibernateException {
+ boolean isProxyUnwrapEnabled = unwrapProxy &&
+ session.getFactory()
+ .getEntityPersister( getAssociatedEntityName() )
+ .isInstrumented( session.getEntityMode() );
+
+ Object proxyOrEntity = session.internalLoad(
+ getAssociatedEntityName(),
+ id,
+ eager,
+ isNullable() && !isProxyUnwrapEnabled
+ );
+
+ if ( proxyOrEntity instanceof HibernateProxy ) {
+ ( ( HibernateProxy ) proxyOrEntity ).getHibernateLazyInitializer()
+ .setUnwrap( isProxyUnwrapEnabled );
+ }
+
+ return proxyOrEntity;
+ }
+
+ protected boolean isNull(Object owner, SessionImplementor session) {
+ return false;
+ }
+
+ /**
+ * Load an instance by a unique key that is not the primary key.
+ *
+ * @param entityName The name of the entity to load
+ * @param uniqueKeyPropertyName The name of the property defining the uniqie key.
+ * @param key The unique key property value.
+ * @param session The originating session.
+ * @return The loaded entity
+ * @throws HibernateException generally indicates problems performing the load.
+ */
+ public Object loadByUniqueKey(
+ String entityName,
+ String uniqueKeyPropertyName,
+ Object key,
+ SessionImplementor session) throws HibernateException {
+ final SessionFactoryImplementor factory = session.getFactory();
+ UniqueKeyLoadable persister = ( UniqueKeyLoadable ) factory.getEntityPersister( entityName );
+
+ //TODO: implement caching?! proxies?!
+
+ EntityUniqueKey euk = new EntityUniqueKey(
+ entityName,
+ uniqueKeyPropertyName,
+ key,
+ getIdentifierOrUniqueKeyType( factory ),
+ session.getEntityMode(),
+ session.getFactory()
+ );
+
+ final PersistenceContext persistenceContext = session.getPersistenceContext();
+ Object result = persistenceContext.getEntity( euk );
+ if ( result == null ) {
+ result = persister.loadByUniqueKey( uniqueKeyPropertyName, key, session );
+ }
+ return result == null ? null : persistenceContext.proxyFor( result );
+ }
+
}
Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/AbstractOperationTestCase.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/AbstractOperationTestCase.java 2006-11-08 16:56:52 UTC (rev 10775)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/AbstractOperationTestCase.java 2006-11-08 22:02:07 UTC (rev 10776)
@@ -1,11 +1,8 @@
package org.hibernate.test.ops;
-import java.util.Iterator;
-
import org.hibernate.test.TestCase;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
-import org.hibernate.Session;
/**
* {@inheritDoc}
@@ -23,7 +20,7 @@
}
protected String[] getMappings() {
- return new String[] { "ops/Node.hbm.xml", "ops/Employer.hbm.xml", "ops/OptLockEntity.hbm.xml" };
+ return new String[] { "ops/Node.hbm.xml", "ops/Employer.hbm.xml", "ops/OptLockEntity.hbm.xml", "ops/OneToOne.hbm.xml" };
}
public String getCacheConcurrencyStrategy() {
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Address.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Address.java 2006-11-08 16:56:52 UTC (rev 10775)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Address.java 2006-11-08 22:02:07 UTC (rev 10776)
@@ -0,0 +1,65 @@
+package org.hibernate.test.ops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Address {
+ private Long id;
+ private String streetAddress;
+ private String city;
+ private String country;
+ private Person resident;
+
+ public Address() {
+ }
+
+ public Address(String streetAddress, String city, String country, Person resident) {
+ this.streetAddress = streetAddress;
+ this.city = city;
+ this.country = country;
+ this.resident = resident;
+ resident.setAddress( this );
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getStreetAddress() {
+ return streetAddress;
+ }
+
+ public void setStreetAddress(String streetAddress) {
+ this.streetAddress = streetAddress;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public Person getResident() {
+ return resident;
+ }
+
+ public void setResident(Person resident) {
+ this.resident = resident;
+ }
+}
Modified: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/MergeTest.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/MergeTest.java 2006-11-08 16:56:52 UTC (rev 10775)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/MergeTest.java 2006-11-08 22:02:07 UTC (rev 10776)
@@ -26,9 +26,69 @@
return new TestSuite( MergeTest.class );
}
- public void testNoExtraUpdatesOnMerge() throws Exception {
+ public void testMergeBidiPrimayKeyOneToOne() throws Exception {
Session s = openSession();
s.beginTransaction();
+ Person p = new Person( "steve" );
+ new PersonalDetails( "I have big feet", p );
+ s.persist( p );
+ s.getTransaction().commit();
+ s.close();
+
+ clearCounts();
+
+ p.getDetails().setSomePersonalDetail( p.getDetails().getSomePersonalDetail() + " and big hands too" );
+ s = openSession();
+ s.beginTransaction();
+ p = ( Person ) s.merge( p );
+ s.getTransaction().commit();
+ s.close();
+
+ assertInsertCount( 0 );
+ assertUpdateCount( 1 );
+ assertDeleteCount( 0 );
+
+ s = openSession();
+ s.beginTransaction();
+ s.delete( p );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testMergeBidiForeignKeyOneToOne() throws Exception {
+ Session s = openSession();
+ s.beginTransaction();
+ Person p = new Person( "steve" );
+ Address a = new Address( "123 Main", "Austin", "US", p );
+ s.persist( a );
+ s.persist( p );
+ s.getTransaction().commit();
+ s.close();
+
+ clearCounts();
+
+ p.getAddress().setStreetAddress( "321 Main" );
+ s = openSession();
+ s.beginTransaction();
+ p = ( Person ) s.merge( p );
+ s.getTransaction().commit();
+ s.close();
+
+ assertInsertCount( 0 );
+ assertUpdateCount( 0 ); // no cascade
+ assertDeleteCount( 0 );
+
+ s = openSession();
+ s.beginTransaction();
+ s.delete( a );
+ s.delete( p );
+ s.getTransaction().commit();
+ s.close();
+ }
+
+ public void testNoExtraUpdatesOnMerge() throws Exception {
+ Session s = openSession();
+ s.beginTransaction();
Node node = new Node( "test" );
s.persist( node );
s.getTransaction().commit();
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/OneToOne.hbm.xml
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/OneToOne.hbm.xml 2006-11-08 16:56:52 UTC (rev 10775)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/OneToOne.hbm.xml 2006-11-08 22:02:07 UTC (rev 10776)
@@ -0,0 +1,43 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<!--
+ Mappings demonstrating bidirectional one-to-one mappings for testing
+ with various operations.
+
+ Person -> Address is modeled as a bidirectional one to one based on FK.
+ Person -> Details is modeled as a bidirectional one to one based on PK.
+-->
+
+<hibernate-mapping package="org.hibernate.test.ops">
+
+ <class name="Person" table="OPS_PERSON">
+ <id name="id" column="ID" type="long">
+ <generator class="increment"/>
+ </id>
+ <property name="name" column="NAME" type="string"/>
+ <one-to-one name="address" class="Address" property-ref="resident" />
+ <one-to-one name="details" class="PersonalDetails" cascade="all" />
+ </class>
+
+ <class name="Address" table="OPS_ADDRESS">
+ <id name="id" column="ID" type="long">
+ <generator class="increment"/>
+ </id>
+ <property name="streetAddress" column="STREET" type="string" />
+ <property name="city" column="CITY" type="string" />
+ <property name="country" column="CTRY" type="string" />
+ <many-to-one name="resident" column="RESIDENT" class="Person" />
+ </class>
+
+ <class name="PersonalDetails" table="OPS_PERS_DETAIL">
+ <id name="id" column="ID" type="long">
+ <generator class="increment"/>
+ </id>
+ <property name="somePersonalDetail" column="SOME_DETAIL" type="string"/>
+ <one-to-one name="person" class="Person" cascade="none" constrained="true" />
+ </class>
+
+</hibernate-mapping>
\ No newline at end of file
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Person.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Person.java 2006-11-08 16:56:52 UTC (rev 10775)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/Person.java 2006-11-08 22:02:07 UTC (rev 10776)
@@ -0,0 +1,52 @@
+package org.hibernate.test.ops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class Person {
+ private Long id;
+ private String name;
+ private Address address;
+ private PersonalDetails details;
+
+ public Person() {
+ }
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+
+ public PersonalDetails getDetails() {
+ return details;
+ }
+
+ public void setDetails(PersonalDetails details) {
+ this.details = details;
+ }
+}
Added: branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/PersonalDetails.java
===================================================================
--- branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/PersonalDetails.java 2006-11-08 16:56:52 UTC (rev 10775)
+++ branches/Branch_3_2/Hibernate3/test/org/hibernate/test/ops/PersonalDetails.java 2006-11-08 22:02:07 UTC (rev 10776)
@@ -0,0 +1,45 @@
+package org.hibernate.test.ops;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class PersonalDetails {
+ private Long id;
+ private String somePersonalDetail;
+ private Person person;
+
+ public PersonalDetails() {
+ }
+
+ public PersonalDetails(String somePersonalDetail, Person person) {
+ this.somePersonalDetail = somePersonalDetail;
+ this.person = person;
+ person.setDetails( this );
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getSomePersonalDetail() {
+ return somePersonalDetail;
+ }
+
+ public void setSomePersonalDetail(String somePersonalDetail) {
+ this.somePersonalDetail = somePersonalDetail;
+ }
+
+ public Person getPerson() {
+ return person;
+ }
+
+ public void setPerson(Person person) {
+ this.person = person;
+ }
+}
More information about the hibernate-commits
mailing list