HHH-4726 - Add support for delete-orphan cascading to <one-to-one/>
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18568 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
7fa50f7a18
commit
29152a8390
|
@ -1064,10 +1064,10 @@ public final class HbmBinder {
|
||||||
// COLUMN(S)
|
// COLUMN(S)
|
||||||
Attribute columnAttribute = node.attribute( "column" );
|
Attribute columnAttribute = node.attribute( "column" );
|
||||||
if ( columnAttribute == null ) {
|
if ( columnAttribute == null ) {
|
||||||
Iterator iter = node.elementIterator();
|
Iterator itr = node.elementIterator();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while ( iter.hasNext() ) {
|
while ( itr.hasNext() ) {
|
||||||
Element columnElement = (Element) iter.next();
|
Element columnElement = (Element) itr.next();
|
||||||
if ( columnElement.getName().equals( "column" ) ) {
|
if ( columnElement.getName().equals( "column" ) ) {
|
||||||
Column column = new Column();
|
Column column = new Column();
|
||||||
column.setValue( simpleValue );
|
column.setValue( simpleValue );
|
||||||
|
@ -1115,6 +1115,9 @@ public final class HbmBinder {
|
||||||
Column column = new Column();
|
Column column = new Column();
|
||||||
column.setValue( simpleValue );
|
column.setValue( simpleValue );
|
||||||
bindColumn( node, column, isNullable );
|
bindColumn( node, column, isNullable );
|
||||||
|
if ( column.isUnique() && ManyToOne.class.isInstance( simpleValue ) ) {
|
||||||
|
( (ManyToOne) simpleValue ).markAsLogicalOneToOne();
|
||||||
|
}
|
||||||
final String columnName = columnAttribute.getValue();
|
final String columnName = columnAttribute.getValue();
|
||||||
String logicalColumnName = mappings.getNamingStrategy().logicalColumnName(
|
String logicalColumnName = mappings.getNamingStrategy().logicalColumnName(
|
||||||
columnName, propertyPath
|
columnName, propertyPath
|
||||||
|
@ -1617,7 +1620,9 @@ public final class HbmBinder {
|
||||||
|
|
||||||
String cascade = node.attributeValue( "cascade" );
|
String cascade = node.attributeValue( "cascade" );
|
||||||
if ( cascade != null && cascade.indexOf( "delete-orphan" ) >= 0 ) {
|
if ( cascade != null && cascade.indexOf( "delete-orphan" ) >= 0 ) {
|
||||||
throw new MappingException( "many-to-one attributes do not support orphan delete: " + path );
|
if ( !manyToOne.isLogicalOneToOne() ) {
|
||||||
|
throw new MappingException( "many-to-one attributes do not support orphan delete: " + path );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,13 +20,14 @@
|
||||||
* 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.engine;
|
package org.hibernate.engine;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -36,6 +37,7 @@ import org.hibernate.collection.PersistentCollection;
|
||||||
import org.hibernate.event.EventSource;
|
import org.hibernate.event.EventSource;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.pretty.MessageHelper;
|
||||||
import org.hibernate.type.AbstractComponentType;
|
import org.hibernate.type.AbstractComponentType;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
import org.hibernate.type.CollectionType;
|
import org.hibernate.type.CollectionType;
|
||||||
|
@ -148,7 +150,8 @@ public final class Cascade {
|
||||||
EntityMode entityMode = eventSource.getEntityMode();
|
EntityMode entityMode = eventSource.getEntityMode();
|
||||||
boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent, entityMode );
|
boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent, entityMode );
|
||||||
for ( int i=0; i<types.length; i++) {
|
for ( int i=0; i<types.length; i++) {
|
||||||
CascadeStyle style = cascadeStyles[i];
|
final CascadeStyle style = cascadeStyles[i];
|
||||||
|
final String propertyName = persister.getPropertyNames()[i];
|
||||||
if ( hasUninitializedLazyProperties && persister.getPropertyLaziness()[i] && ! action.performOnLazyProperty() ) {
|
if ( hasUninitializedLazyProperties && persister.getPropertyLaziness()[i] && ! action.performOnLazyProperty() ) {
|
||||||
//do nothing to avoid a lazy property initialization
|
//do nothing to avoid a lazy property initialization
|
||||||
continue;
|
continue;
|
||||||
|
@ -160,6 +163,7 @@ public final class Cascade {
|
||||||
persister.getPropertyValue( parent, i, entityMode ),
|
persister.getPropertyValue( parent, i, entityMode ),
|
||||||
types[i],
|
types[i],
|
||||||
style,
|
style,
|
||||||
|
propertyName,
|
||||||
anything,
|
anything,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
@ -189,6 +193,7 @@ public final class Cascade {
|
||||||
final Object child,
|
final Object child,
|
||||||
final Type type,
|
final Type type,
|
||||||
final CascadeStyle style,
|
final CascadeStyle style,
|
||||||
|
final String propertyName,
|
||||||
final Object anything,
|
final Object anything,
|
||||||
final boolean isCascadeDeleteEnabled) throws HibernateException {
|
final boolean isCascadeDeleteEnabled) throws HibernateException {
|
||||||
|
|
||||||
|
@ -207,7 +212,7 @@ public final class Cascade {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( type.isComponentType() ) {
|
else if ( type.isComponentType() ) {
|
||||||
cascadeComponent( parent, child, (AbstractComponentType) type, anything );
|
cascadeComponent( parent, child, (AbstractComponentType) type, propertyName, anything );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -222,11 +227,34 @@ public final class Cascade {
|
||||||
final EntityEntry entry = eventSource.getPersistenceContext().getEntry( parent );
|
final EntityEntry entry = eventSource.getPersistenceContext().getEntry( parent );
|
||||||
if ( entry != null ) {
|
if ( entry != null ) {
|
||||||
final EntityType entityType = (EntityType) type;
|
final EntityType entityType = (EntityType) type;
|
||||||
final Object loadedValue = entry.getLoadedValue( entityType.getPropertyName() );
|
final Object loadedValue;
|
||||||
|
if ( componentPathStack.isEmpty() ) {
|
||||||
|
// association defined on entity
|
||||||
|
loadedValue = entry.getLoadedValue( propertyName );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// association defined on component
|
||||||
|
// todo : this is currently unsupported because of the fact that
|
||||||
|
// we do not know the loaded state of this value properly
|
||||||
|
// and doing so would be very difficult given how components and
|
||||||
|
// entities are loaded (and how 'loaded state' is put into the
|
||||||
|
// EntityEntry). Solutions here are to either:
|
||||||
|
// 1) properly account for components as a 2-phase load construct
|
||||||
|
// 2) just assume the association was just now orphaned and
|
||||||
|
// issue the orphan delete. This would require a special
|
||||||
|
// set of SQL statements though since we do not know the
|
||||||
|
// orphaned value, something a delete with a subquery to
|
||||||
|
// match the owner.
|
||||||
|
// final String propertyPath = composePropertyPath( entityType.getPropertyName() );
|
||||||
|
loadedValue = null;
|
||||||
|
}
|
||||||
if ( loadedValue != null ) {
|
if ( loadedValue != null ) {
|
||||||
final String entityName = entityType.getAssociatedEntityName();
|
final String entityName = entry.getPersister().getEntityName();
|
||||||
if ( log.isTraceEnabled() ) {
|
if ( log.isTraceEnabled() ) {
|
||||||
log.trace( "deleting orphaned entity instance: " + entityName );
|
final Serializable id = entry.getPersister()
|
||||||
|
.getIdentifier( loadedValue, eventSource.getEntityMode() );
|
||||||
|
final String description = MessageHelper.infoString( entityName, id );
|
||||||
|
log.trace( "deleting orphaned entity instance: " + description );
|
||||||
}
|
}
|
||||||
eventSource.delete( entityName, loadedValue, false, new HashSet() );
|
eventSource.delete( entityName, loadedValue, false, new HashSet() );
|
||||||
}
|
}
|
||||||
|
@ -245,21 +273,26 @@ public final class Cascade {
|
||||||
* @return True if the attribute represents a logical one to one association
|
* @return True if the attribute represents a logical one to one association
|
||||||
*/
|
*/
|
||||||
private boolean isLogicalOneToOne(Type type) {
|
private boolean isLogicalOneToOne(Type type) {
|
||||||
if ( ! type.isEntityType() ) {
|
return type.isEntityType() && ( (EntityType) type ).isLogicalOneToOne();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final EntityType entityType = (EntityType) type;
|
|
||||||
if ( entityType.isOneToOne() ) {
|
|
||||||
// physical one-to-one
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// todo : still need to handle the many-to-one w/ property-ref
|
|
||||||
// actually there is a question about whether the constrained side
|
|
||||||
// can declare the orphan-delete. If not, then the side declaring
|
|
||||||
// the orphan-delete can only ever be a <one-to-one/>
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String composePropertyPath(String propertyName) {
|
||||||
|
if ( componentPathStack.isEmpty() ) {
|
||||||
|
return propertyName;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
Iterator itr = componentPathStack.iterator();
|
||||||
|
while ( itr.hasNext() ) {
|
||||||
|
buffer.append( itr.next() ).append( '.' );
|
||||||
|
}
|
||||||
|
buffer.append( propertyName );
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stack componentPathStack = new Stack();
|
||||||
|
|
||||||
private boolean cascadeAssociationNow(AssociationType associationType) {
|
private boolean cascadeAssociationNow(AssociationType associationType) {
|
||||||
return associationType.getForeignKeyDirection().cascadeNow(cascadeTo) &&
|
return associationType.getForeignKeyDirection().cascadeNow(cascadeTo) &&
|
||||||
( eventSource.getEntityMode()!=EntityMode.DOM4J || associationType.isEmbeddedInXML() );
|
( eventSource.getEntityMode()!=EntityMode.DOM4J || associationType.isEmbeddedInXML() );
|
||||||
|
@ -269,22 +302,27 @@ public final class Cascade {
|
||||||
final Object parent,
|
final Object parent,
|
||||||
final Object child,
|
final Object child,
|
||||||
final AbstractComponentType componentType,
|
final AbstractComponentType componentType,
|
||||||
|
final String componentPropertyName,
|
||||||
final Object anything) {
|
final Object anything) {
|
||||||
Object[] children = componentType.getPropertyValues(child, eventSource);
|
componentPathStack.push( componentPropertyName );
|
||||||
|
Object[] children = componentType.getPropertyValues( child, eventSource );
|
||||||
Type[] types = componentType.getSubtypes();
|
Type[] types = componentType.getSubtypes();
|
||||||
for ( int i=0; i<types.length; i++ ) {
|
for ( int i=0; i<types.length; i++ ) {
|
||||||
CascadeStyle componentPropertyStyle = componentType.getCascadeStyle(i);
|
final CascadeStyle componentPropertyStyle = componentType.getCascadeStyle(i);
|
||||||
|
final String subPropertyName = componentType.getPropertyNames()[i];
|
||||||
if ( componentPropertyStyle.doCascade(action) ) {
|
if ( componentPropertyStyle.doCascade(action) ) {
|
||||||
cascadeProperty(
|
cascadeProperty(
|
||||||
parent,
|
parent,
|
||||||
children[i],
|
children[i],
|
||||||
types[i],
|
types[i],
|
||||||
componentPropertyStyle,
|
componentPropertyStyle,
|
||||||
|
subPropertyName,
|
||||||
anything,
|
anything,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
componentPathStack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cascadeAssociation(
|
private void cascadeAssociation(
|
||||||
|
@ -389,7 +427,8 @@ public final class Cascade {
|
||||||
parent,
|
parent,
|
||||||
iter.next(),
|
iter.next(),
|
||||||
elemType,
|
elemType,
|
||||||
style,
|
style,
|
||||||
|
null,
|
||||||
anything,
|
anything,
|
||||||
isCascadeDeleteEnabled
|
isCascadeDeleteEnabled
|
||||||
);
|
);
|
||||||
|
|
|
@ -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.engine;
|
package org.hibernate.engine;
|
||||||
|
|
||||||
|
@ -29,7 +28,6 @@ import java.io.ObjectOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
|
|
||||||
|
|
||||||
import org.hibernate.EntityMode;
|
import org.hibernate.EntityMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
@ -84,13 +82,9 @@ public final class EntityEntry implements Serializable {
|
||||||
this.loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
|
this.loadedWithLazyPropertiesUnfetched = lazyPropertiesAreUnfetched;
|
||||||
this.persister=persister;
|
this.persister=persister;
|
||||||
this.entityMode = entityMode;
|
this.entityMode = entityMode;
|
||||||
this.entityName = persister == null ?
|
this.entityName = persister == null ? null : persister.getEntityName();
|
||||||
null : persister.getEntityName();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used during custom deserialization
|
|
||||||
*/
|
|
||||||
private EntityEntry(
|
private EntityEntry(
|
||||||
final SessionFactoryImplementor factory,
|
final SessionFactoryImplementor factory,
|
||||||
final String entityName,
|
final String entityName,
|
||||||
|
@ -104,6 +98,7 @@ public final class EntityEntry implements Serializable {
|
||||||
final boolean existsInDatabase,
|
final boolean existsInDatabase,
|
||||||
final boolean isBeingReplicated,
|
final boolean isBeingReplicated,
|
||||||
final boolean loadedWithLazyPropertiesUnfetched) {
|
final boolean loadedWithLazyPropertiesUnfetched) {
|
||||||
|
// Used during custom deserialization
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.persister = ( factory == null ? null : factory.getEntityPersister( entityName ) );
|
this.persister = ( factory == null ? null : factory.getEntityPersister( entityName ) );
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
@ -181,10 +176,6 @@ public final class EntityEntry implements Serializable {
|
||||||
return cachedEntityKey;
|
return cachedEntityKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
void afterDeserialize(SessionFactoryImplementor factory) {
|
|
||||||
persister = factory.getEntityPersister( entityName );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEntityName() {
|
public String getEntityName() {
|
||||||
return entityName;
|
return entityName;
|
||||||
}
|
}
|
||||||
|
@ -198,24 +189,29 @@ public final class EntityEntry implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After actually updating the database, update the snapshot information,
|
* Handle updating the internal state of the entry after actually performing
|
||||||
* and escalate the lock mode
|
* the database update. Specifically we update the snapshot information and
|
||||||
|
* escalate the lock mode
|
||||||
|
*
|
||||||
|
* @param entity The entity instance
|
||||||
|
* @param updatedState The state calculated after the update (becomes the
|
||||||
|
* new {@link #getLoadedState() loaded state}.
|
||||||
|
* @param nextVersion The new version.
|
||||||
*/
|
*/
|
||||||
public void postUpdate(Object entity, Object[] updatedState, Object nextVersion) {
|
public void postUpdate(Object entity, Object[] updatedState, Object nextVersion) {
|
||||||
this.loadedState = updatedState;
|
this.loadedState = updatedState;
|
||||||
|
|
||||||
setLockMode(LockMode.WRITE);
|
setLockMode(LockMode.WRITE);
|
||||||
|
|
||||||
if ( getPersister().isVersioned() ) {
|
if ( getPersister().isVersioned() ) {
|
||||||
this.version = nextVersion;
|
this.version = nextVersion;
|
||||||
getPersister().setPropertyValue(
|
getPersister().setPropertyValue(
|
||||||
entity,
|
entity,
|
||||||
getPersister().getVersionProperty(),
|
getPersister().getVersionProperty(),
|
||||||
nextVersion,
|
nextVersion,
|
||||||
entityMode
|
entityMode
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldInterceptionHelper.clearDirty( entity );
|
FieldInterceptionHelper.clearDirty( entity );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,8 +245,7 @@ public final class EntityEntry implements Serializable {
|
||||||
int propertyIndex = ( (UniqueKeyLoadable) persister ).getPropertyIndex(propertyName);
|
int propertyIndex = ( (UniqueKeyLoadable) persister ).getPropertyIndex(propertyName);
|
||||||
return loadedState[propertyIndex];
|
return loadedState[propertyIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean requiresDirtyCheck(Object entity) {
|
public boolean requiresDirtyCheck(Object entity) {
|
||||||
|
|
||||||
boolean isMutableInstance =
|
boolean isMutableInstance =
|
||||||
|
@ -268,6 +263,7 @@ public final class EntityEntry implements Serializable {
|
||||||
public void forceLocked(Object entity, Object nextVersion) {
|
public void forceLocked(Object entity, Object nextVersion) {
|
||||||
version = nextVersion;
|
version = nextVersion;
|
||||||
loadedState[ persister.getVersionProperty() ] = version;
|
loadedState[ persister.getVersionProperty() ] = version;
|
||||||
|
//noinspection deprecation
|
||||||
setLockMode( LockMode.FORCE ); // TODO: use LockMode.PESSIMISTIC_FORCE_INCREMENT
|
setLockMode( LockMode.FORCE ); // TODO: use LockMode.PESSIMISTIC_FORCE_INCREMENT
|
||||||
persister.setPropertyValue(
|
persister.setPropertyValue(
|
||||||
entity,
|
entity,
|
||||||
|
@ -309,13 +305,13 @@ public final class EntityEntry implements Serializable {
|
||||||
return loadedWithLazyPropertiesUnfetched;
|
return loadedWithLazyPropertiesUnfetched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom serialization routine used during serialization of a
|
* Custom serialization routine used during serialization of a
|
||||||
* Session/PersistenceContext for increased performance.
|
* Session/PersistenceContext for increased performance.
|
||||||
*
|
*
|
||||||
* @param oos The stream to which we should write the serial data.
|
* @param oos The stream to which we should write the serial data.
|
||||||
* @throws java.io.IOException
|
*
|
||||||
|
* @throws IOException If a stream error occurs
|
||||||
*/
|
*/
|
||||||
void serialize(ObjectOutputStream oos) throws IOException {
|
void serialize(ObjectOutputStream oos) throws IOException {
|
||||||
oos.writeObject( entityName );
|
oos.writeObject( entityName );
|
||||||
|
@ -338,9 +334,12 @@ public final class EntityEntry implements Serializable {
|
||||||
*
|
*
|
||||||
* @param ois The stream from which to read the entry.
|
* @param ois The stream from which to read the entry.
|
||||||
* @param session The session being deserialized.
|
* @param session The session being deserialized.
|
||||||
|
*
|
||||||
* @return The deserialized EntityEntry
|
* @return The deserialized EntityEntry
|
||||||
* @throws IOException
|
*
|
||||||
* @throws ClassNotFoundException
|
* @throws IOException If a stream error occurs
|
||||||
|
* @throws ClassNotFoundException If any of the classes declared in the stream
|
||||||
|
* cannot be found
|
||||||
*/
|
*/
|
||||||
static EntityEntry deserialize(
|
static EntityEntry deserialize(
|
||||||
ObjectInputStream ois,
|
ObjectInputStream ois,
|
||||||
|
@ -353,7 +352,7 @@ public final class EntityEntry implements Serializable {
|
||||||
Status.parse( ( String ) ois.readObject() ),
|
Status.parse( ( String ) ois.readObject() ),
|
||||||
( Object[] ) ois.readObject(),
|
( Object[] ) ois.readObject(),
|
||||||
( Object[] ) ois.readObject(),
|
( Object[] ) ois.readObject(),
|
||||||
( Object ) ois.readObject(),
|
ois.readObject(),
|
||||||
LockMode.parse( ( String ) ois.readObject() ),
|
LockMode.parse( ( String ) ois.readObject() ),
|
||||||
ois.readBoolean(),
|
ois.readBoolean(),
|
||||||
ois.readBoolean(),
|
ois.readBoolean(),
|
||||||
|
|
|
@ -38,8 +38,8 @@ import org.hibernate.type.TypeFactory;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class ManyToOne extends ToOne {
|
public class ManyToOne extends ToOne {
|
||||||
|
|
||||||
private boolean ignoreNotFound;
|
private boolean ignoreNotFound;
|
||||||
|
private boolean isLogicalOneToOne;
|
||||||
|
|
||||||
public ManyToOne(Table table) {
|
public ManyToOne(Table table) {
|
||||||
super(table);
|
super(table);
|
||||||
|
@ -52,8 +52,9 @@ public class ManyToOne extends ToOne {
|
||||||
isLazy(),
|
isLazy(),
|
||||||
isUnwrapProxy(),
|
isUnwrapProxy(),
|
||||||
isEmbedded(),
|
isEmbedded(),
|
||||||
isIgnoreNotFound()
|
isIgnoreNotFound(),
|
||||||
);
|
isLogicalOneToOne
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createForeignKey() throws MappingException {
|
public void createForeignKey() throws MappingException {
|
||||||
|
@ -110,5 +111,11 @@ public class ManyToOne extends ToOne {
|
||||||
this.ignoreNotFound = ignoreNotFound;
|
this.ignoreNotFound = ignoreNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void markAsLogicalOneToOne() {
|
||||||
|
this.isLogicalOneToOne = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLogicalOneToOne() {
|
||||||
|
return isLogicalOneToOne;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.tuple.entity;
|
package org.hibernate.tuple.entity;
|
||||||
|
|
||||||
|
@ -29,7 +28,6 @@ import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.EntityMode;
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.tuple.Instantiator;
|
import org.hibernate.tuple.Instantiator;
|
||||||
|
@ -132,12 +130,12 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
getters = new Getter[propertySpan];
|
getters = new Getter[propertySpan];
|
||||||
setters = new Setter[propertySpan];
|
setters = new Setter[propertySpan];
|
||||||
|
|
||||||
Iterator iter = mappingInfo.getPropertyClosureIterator();
|
Iterator itr = mappingInfo.getPropertyClosureIterator();
|
||||||
boolean foundCustomAccessor=false;
|
boolean foundCustomAccessor=false;
|
||||||
int i=0;
|
int i=0;
|
||||||
while ( iter.hasNext() ) {
|
while ( itr.hasNext() ) {
|
||||||
//TODO: redesign how PropertyAccessors are acquired...
|
//TODO: redesign how PropertyAccessors are acquired...
|
||||||
Property property = (Property) iter.next();
|
Property property = (Property) itr.next();
|
||||||
getters[i] = buildPropertyGetter(property, mappingInfo);
|
getters[i] = buildPropertyGetter(property, mappingInfo);
|
||||||
setters[i] = buildPropertySetter(property, mappingInfo);
|
setters[i] = buildPropertySetter(property, mappingInfo);
|
||||||
if ( !property.isBasicPropertyAccessor() ) {
|
if ( !property.isBasicPropertyAccessor() ) {
|
||||||
|
@ -172,7 +170,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retreives the defined entity-names for any subclasses defined for this
|
* Retrieves the defined entity-names for any subclasses defined for this
|
||||||
* entity.
|
* entity.
|
||||||
*
|
*
|
||||||
* @return Any subclass entity-names.
|
* @return Any subclass entity-names.
|
||||||
|
@ -208,7 +206,7 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
catch ( ClassCastException cce ) {
|
catch ( ClassCastException cce ) {
|
||||||
StringBuffer msg = new StringBuffer( "Identifier classes must be serializable. " );
|
StringBuffer msg = new StringBuffer( "Identifier classes must be serializable. " );
|
||||||
if ( id != null ) {
|
if ( id != null ) {
|
||||||
msg.append( id.getClass().getName() + " is not serializable. " );
|
msg.append( id.getClass().getName() ).append( " is not serializable. " );
|
||||||
}
|
}
|
||||||
if ( cce.getMessage() != null ) {
|
if ( cce.getMessage() != null ) {
|
||||||
msg.append( cce.getMessage() );
|
msg.append( cce.getMessage() );
|
||||||
|
@ -296,16 +294,21 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getPropertyValue(Object entity, String propertyPath) throws HibernateException {
|
public Object getPropertyValue(Object entity, String propertyPath) throws HibernateException {
|
||||||
|
final int loc = propertyPath.indexOf('.');
|
||||||
int loc = propertyPath.indexOf('.');
|
final String basePropertyName = loc > 0
|
||||||
String basePropertyName = loc>0 ?
|
? propertyPath.substring( 0, loc )
|
||||||
propertyPath.substring(0, loc) : propertyPath;
|
: propertyPath;
|
||||||
|
final int index = entityMetamodel.getPropertyIndex( basePropertyName );
|
||||||
int index = entityMetamodel.getPropertyIndex( basePropertyName );
|
final Object baseValue = getPropertyValue( entity, index );
|
||||||
Object baseValue = getPropertyValue( entity, index );
|
if ( loc > 0 ) {
|
||||||
if ( loc>0 ) {
|
if ( baseValue == null ) {
|
||||||
ComponentType type = (ComponentType) entityMetamodel.getPropertyTypes()[index];
|
return null;
|
||||||
return getComponentValue( type, baseValue, propertyPath.substring(loc+1) );
|
}
|
||||||
|
return getComponentValue(
|
||||||
|
(ComponentType) entityMetamodel.getPropertyTypes()[index],
|
||||||
|
baseValue,
|
||||||
|
propertyPath.substring(loc+1)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return baseValue;
|
return baseValue;
|
||||||
|
@ -321,25 +324,21 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
* @return The property value extracted.
|
* @return The property value extracted.
|
||||||
*/
|
*/
|
||||||
protected Object getComponentValue(ComponentType type, Object component, String propertyPath) {
|
protected Object getComponentValue(ComponentType type, Object component, String propertyPath) {
|
||||||
|
final int loc = propertyPath.indexOf( '.' );
|
||||||
int loc = propertyPath.indexOf('.');
|
final String basePropertyName = loc > 0
|
||||||
String basePropertyName = loc>0 ?
|
? propertyPath.substring( 0, loc )
|
||||||
propertyPath.substring(0, loc) : propertyPath;
|
: propertyPath;
|
||||||
|
final int index = findSubPropertyIndex( type, basePropertyName );
|
||||||
String[] propertyNames = type.getPropertyNames();
|
final Object baseValue = type.getPropertyValue( component, index, getEntityMode() );
|
||||||
int index=0;
|
if ( loc > 0 ) {
|
||||||
for ( ; index<propertyNames.length; index++ ) {
|
if ( baseValue == null ) {
|
||||||
if ( basePropertyName.equals( propertyNames[index] ) ) break;
|
return null;
|
||||||
}
|
}
|
||||||
if (index==propertyNames.length) {
|
return getComponentValue(
|
||||||
throw new MappingException( "component property not found: " + basePropertyName );
|
(ComponentType) type.getSubtypes()[index],
|
||||||
}
|
baseValue,
|
||||||
|
propertyPath.substring(loc+1)
|
||||||
Object baseValue = type.getPropertyValue( component, index, getEntityMode() );
|
);
|
||||||
|
|
||||||
if ( loc>0 ) {
|
|
||||||
ComponentType subtype = (ComponentType) type.getSubtypes()[index];
|
|
||||||
return getComponentValue( subtype, baseValue, propertyPath.substring(loc+1) );
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return baseValue;
|
return baseValue;
|
||||||
|
@ -347,6 +346,16 @@ public abstract class AbstractEntityTuplizer implements EntityTuplizer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int findSubPropertyIndex(ComponentType type, String subPropertyName) {
|
||||||
|
final String[] propertyNames = type.getPropertyNames();
|
||||||
|
for ( int index = 0; index<propertyNames.length; index++ ) {
|
||||||
|
if ( subPropertyName.equals( propertyNames[index] ) ) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new MappingException( "component property not found: " + subPropertyName );
|
||||||
|
}
|
||||||
|
|
||||||
public void setPropertyValues(Object entity, Object[] values) throws HibernateException {
|
public void setPropertyValues(Object entity, Object[] values) throws HibernateException {
|
||||||
boolean setAll = !entityMetamodel.hasLazyProperties();
|
boolean setAll = !entityMetamodel.hasLazyProperties();
|
||||||
|
|
||||||
|
|
|
@ -508,8 +508,22 @@ public abstract class EntityType extends AbstractType implements AssociationType
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the association modeled here defined as a 1-1 in the database (physical model)?
|
||||||
|
*
|
||||||
|
* @return True if a 1-1 in the database; false otherwise.
|
||||||
|
*/
|
||||||
public abstract boolean isOneToOne();
|
public abstract boolean isOneToOne();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the association modeled here a 1-1 according to the logical moidel?
|
||||||
|
*
|
||||||
|
* @return True if a 1-1 in the logical model; false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isLogicalOneToOne() {
|
||||||
|
return isOneToOne();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method to locate the identifier type of the associated entity.
|
* Convenience method to locate the identifier type of the associated entity.
|
||||||
*
|
*
|
||||||
|
|
|
@ -45,27 +45,54 @@ import org.hibernate.persister.entity.EntityPersister;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class ManyToOneType extends EntityType {
|
public class ManyToOneType extends EntityType {
|
||||||
|
|
||||||
private final boolean ignoreNotFound;
|
private final boolean ignoreNotFound;
|
||||||
|
private boolean isLogicalOneToOne;
|
||||||
|
|
||||||
public ManyToOneType(String className) {
|
/**
|
||||||
this( className, false );
|
* Creates a many-to-one association type with the given referenced entity.
|
||||||
|
*
|
||||||
|
* @param referencedEntityName The name iof the referenced entity
|
||||||
|
*/
|
||||||
|
public ManyToOneType(String referencedEntityName) {
|
||||||
|
this( referencedEntityName, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ManyToOneType(String className, boolean lazy) {
|
/**
|
||||||
super( className, null, !lazy, true, false );
|
* Creates a many-to-one association type with the given referenced entity and the
|
||||||
this.ignoreNotFound = false;
|
* given laziness characteristic
|
||||||
|
*
|
||||||
|
* @param referencedEntityName The name iof the referenced entity
|
||||||
|
* @param lazy Should the association be handled lazily
|
||||||
|
*/
|
||||||
|
public ManyToOneType(String referencedEntityName, boolean lazy) {
|
||||||
|
this( referencedEntityName, null, !lazy, true, false, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #ManyToOneType(String, String, boolean, boolean, boolean, boolean, boolean)}
|
||||||
|
* @noinspection JavaDoc
|
||||||
|
*/
|
||||||
public ManyToOneType(
|
public ManyToOneType(
|
||||||
String entityName,
|
String referencedEntityName,
|
||||||
String uniqueKeyPropertyName,
|
String uniqueKeyPropertyName,
|
||||||
boolean lazy,
|
boolean lazy,
|
||||||
boolean unwrapProxy,
|
boolean unwrapProxy,
|
||||||
boolean isEmbeddedInXML,
|
boolean isEmbeddedInXML,
|
||||||
boolean ignoreNotFound) {
|
boolean ignoreNotFound) {
|
||||||
super( entityName, uniqueKeyPropertyName, !lazy, isEmbeddedInXML, unwrapProxy );
|
this( referencedEntityName, uniqueKeyPropertyName, !lazy, isEmbeddedInXML, unwrapProxy, ignoreNotFound, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ManyToOneType(
|
||||||
|
String referencedEntityName,
|
||||||
|
String uniqueKeyPropertyName,
|
||||||
|
boolean lazy,
|
||||||
|
boolean unwrapProxy,
|
||||||
|
boolean isEmbeddedInXML,
|
||||||
|
boolean ignoreNotFound,
|
||||||
|
boolean isLogicalOneToOne) {
|
||||||
|
super( referencedEntityName, uniqueKeyPropertyName, !lazy, isEmbeddedInXML, unwrapProxy );
|
||||||
this.ignoreNotFound = ignoreNotFound;
|
this.ignoreNotFound = ignoreNotFound;
|
||||||
|
this.isLogicalOneToOne = isLogicalOneToOne;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isNullable() {
|
protected boolean isNullable() {
|
||||||
|
@ -82,7 +109,11 @@ public class ManyToOneType extends EntityType {
|
||||||
public boolean isOneToOne() {
|
public boolean isOneToOne() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLogicalOneToOne() {
|
||||||
|
return isLogicalOneToOne;
|
||||||
|
}
|
||||||
|
|
||||||
public int getColumnSpan(Mapping mapping) throws MappingException {
|
public int getColumnSpan(Mapping mapping) throws MappingException {
|
||||||
// our column span is the number of columns in the PK
|
// our column span is the number of columns in the PK
|
||||||
return getIdentifierOrUniqueKeyType( mapping ).getColumnSpan( mapping );
|
return getIdentifierOrUniqueKeyType( mapping ).getColumnSpan( mapping );
|
||||||
|
|
|
@ -201,6 +201,8 @@ public final class TypeFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A many-to-one association type for the given class
|
* A many-to-one association type for the given class
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #manyToOne(String, String, boolean, boolean, boolean, boolean, boolean)}
|
||||||
*/
|
*/
|
||||||
public static EntityType manyToOne(
|
public static EntityType manyToOne(
|
||||||
String persistentClass,
|
String persistentClass,
|
||||||
|
@ -208,8 +210,8 @@ public final class TypeFactory {
|
||||||
boolean lazy,
|
boolean lazy,
|
||||||
boolean unwrapProxy,
|
boolean unwrapProxy,
|
||||||
boolean isEmbeddedInXML,
|
boolean isEmbeddedInXML,
|
||||||
boolean ignoreNotFound
|
boolean ignoreNotFound) {
|
||||||
) {
|
//noinspection deprecation
|
||||||
return new ManyToOneType(
|
return new ManyToOneType(
|
||||||
persistentClass,
|
persistentClass,
|
||||||
uniqueKeyPropertyName,
|
uniqueKeyPropertyName,
|
||||||
|
@ -217,7 +219,29 @@ public final class TypeFactory {
|
||||||
unwrapProxy,
|
unwrapProxy,
|
||||||
isEmbeddedInXML,
|
isEmbeddedInXML,
|
||||||
ignoreNotFound
|
ignoreNotFound
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A many-to-one association type for the given class
|
||||||
|
*/
|
||||||
|
public static EntityType manyToOne(
|
||||||
|
String persistentClass,
|
||||||
|
String uniqueKeyPropertyName,
|
||||||
|
boolean lazy,
|
||||||
|
boolean unwrapProxy,
|
||||||
|
boolean isEmbeddedInXML,
|
||||||
|
boolean ignoreNotFound,
|
||||||
|
boolean isLogicalOneToOne) {
|
||||||
|
return new ManyToOneType(
|
||||||
|
persistentClass,
|
||||||
|
uniqueKeyPropertyName,
|
||||||
|
lazy,
|
||||||
|
unwrapProxy,
|
||||||
|
isEmbeddedInXML,
|
||||||
|
ignoreNotFound,
|
||||||
|
isLogicalOneToOne
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -629,6 +629,10 @@ public class CustomPersister implements EntityPersister {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getOrphanRemovalOneToOnePaths() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public Object[] getNaturalIdentifierSnapshot(Serializable id, SessionImplementor session) throws HibernateException {
|
public Object[] getNaturalIdentifierSnapshot(Serializable id, SessionImplementor session) throws HibernateException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.orphan.one2one.fk.reversed.bidirectional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class DeleteOneToOneOrphansTest extends FunctionalTestCase {
|
||||||
|
public DeleteOneToOneOrphansTest(String string) {
|
||||||
|
super( string );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMappings() {
|
||||||
|
return new String[] { "orphan/one2one/fk/reversed/bidirectional/Mapping.hbm.xml" };
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createData() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
Employee emp = new Employee();
|
||||||
|
emp.setInfo( new EmployeeInfo( emp ) );
|
||||||
|
session.save( emp );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanupData() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
session.createQuery( "delete EmployeeInfo" ).executeUpdate();
|
||||||
|
session.createQuery( "delete Employee" ).executeUpdate();
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOrphanedWhileManaged() {
|
||||||
|
createData();
|
||||||
|
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
List results = session.createQuery( "from EmployeeInfo" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
results = session.createQuery( "from Employee" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
Employee emp = ( Employee ) results.get( 0 );
|
||||||
|
assertNotNull( emp.getInfo() );
|
||||||
|
emp.setInfo( null );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
emp = ( Employee ) session.get( Employee.class, emp.getId() );
|
||||||
|
assertNull( emp.getInfo() );
|
||||||
|
results = session.createQuery( "from EmployeeInfo" ).list();
|
||||||
|
assertEquals( 0, results.size() );
|
||||||
|
results = session.createQuery( "from Employee" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
cleanupData();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.orphan.one2one.fk.reversed.bidirectional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class Employee {
|
||||||
|
private Long id;
|
||||||
|
private EmployeeInfo info;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmployeeInfo getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(EmployeeInfo info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.orphan.one2one.fk.reversed.bidirectional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class EmployeeInfo {
|
||||||
|
private Long id;
|
||||||
|
private Employee employee;
|
||||||
|
|
||||||
|
public EmployeeInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmployeeInfo(Employee employee) {
|
||||||
|
this.employee = employee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Employee getEmployee() {
|
||||||
|
return employee;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmployee(Employee employee) {
|
||||||
|
this.employee = employee;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
~
|
||||||
|
~ Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
~ indicated by the @author tags or express copyright attribution
|
||||||
|
~ statements applied by the authors. All third-party contributions are
|
||||||
|
~ distributed under license by Red Hat Inc.
|
||||||
|
~
|
||||||
|
~ 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
|
||||||
|
~ Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
~ for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Lesser General Public License
|
||||||
|
~ along with this distribution; if not, write to:
|
||||||
|
~ Free Software Foundation, Inc.
|
||||||
|
~ 51 Franklin Street, Fifth Floor
|
||||||
|
~ Boston, MA 02110-1301 USA
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!DOCTYPE hibernate-mapping PUBLIC
|
||||||
|
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
|
||||||
|
'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
|
||||||
|
|
||||||
|
<hibernate-mapping package="org.hibernate.test.orphan.one2one.fk.reversed.bidirectional" >
|
||||||
|
|
||||||
|
<class name="Employee">
|
||||||
|
<id name="id" type="long" column="id">
|
||||||
|
<generator class="increment" />
|
||||||
|
</id>
|
||||||
|
<many-to-one name="info"
|
||||||
|
column="info_id"
|
||||||
|
unique="true"
|
||||||
|
cascade="all,delete-orphan"/>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="EmployeeInfo">
|
||||||
|
<id name="id" type="long" column="id">
|
||||||
|
<generator class="increment" />
|
||||||
|
</id>
|
||||||
|
<one-to-one name="employee"
|
||||||
|
property-ref="info"
|
||||||
|
class="Employee" />
|
||||||
|
</class>
|
||||||
|
|
||||||
|
</hibernate-mapping>
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.orphan.one2one.fk.reversed.unidirectional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class DeleteOneToOneOrphansTest extends FunctionalTestCase {
|
||||||
|
public DeleteOneToOneOrphansTest(String string) {
|
||||||
|
super( string );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMappings() {
|
||||||
|
return new String[] { "orphan/one2one/fk/reversed/unidirectional/Mapping.hbm.xml" };
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createData() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
Employee emp = new Employee();
|
||||||
|
emp.setInfo( new EmployeeInfo() );
|
||||||
|
session.save( emp );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanupData() {
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
session.createQuery( "delete EmployeeInfo" ).executeUpdate();
|
||||||
|
session.createQuery( "delete Employee" ).executeUpdate();
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOrphanedWhileManaged() {
|
||||||
|
createData();
|
||||||
|
|
||||||
|
Session session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
List results = session.createQuery( "from EmployeeInfo" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
results = session.createQuery( "from Employee" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
Employee emp = ( Employee ) results.get( 0 );
|
||||||
|
assertNotNull( emp.getInfo() );
|
||||||
|
emp.setInfo( null );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
session = openSession();
|
||||||
|
session.beginTransaction();
|
||||||
|
emp = ( Employee ) session.get( Employee.class, emp.getId() );
|
||||||
|
assertNull( emp.getInfo() );
|
||||||
|
results = session.createQuery( "from EmployeeInfo" ).list();
|
||||||
|
assertEquals( 0, results.size() );
|
||||||
|
results = session.createQuery( "from Employee" ).list();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
session.getTransaction().commit();
|
||||||
|
session.close();
|
||||||
|
|
||||||
|
cleanupData();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.orphan.one2one.fk.reversed.unidirectional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class Employee {
|
||||||
|
private Long id;
|
||||||
|
private EmployeeInfo info;
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmployeeInfo getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInfo(EmployeeInfo info) {
|
||||||
|
this.info = info;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Inc.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.orphan.one2one.fk.reversed.unidirectional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO : javadoc
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class EmployeeInfo {
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
public EmployeeInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
~
|
||||||
|
~ Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||||
|
~ indicated by the @author tags or express copyright attribution
|
||||||
|
~ statements applied by the authors. All third-party contributions are
|
||||||
|
~ distributed under license by Red Hat Inc.
|
||||||
|
~
|
||||||
|
~ 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
|
||||||
|
~ Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
~ for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Lesser General Public License
|
||||||
|
~ along with this distribution; if not, write to:
|
||||||
|
~ Free Software Foundation, Inc.
|
||||||
|
~ 51 Franklin Street, Fifth Floor
|
||||||
|
~ Boston, MA 02110-1301 USA
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!DOCTYPE hibernate-mapping PUBLIC
|
||||||
|
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
|
||||||
|
'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
|
||||||
|
|
||||||
|
<hibernate-mapping package="org.hibernate.test.orphan.one2one.fk.reversed.unidirectional" >
|
||||||
|
|
||||||
|
<class name="Employee">
|
||||||
|
<id name="id" type="long" column="id">
|
||||||
|
<generator class="increment" />
|
||||||
|
</id>
|
||||||
|
<many-to-one name="info"
|
||||||
|
column="info_id"
|
||||||
|
unique="true"
|
||||||
|
cascade="all,delete-orphan"/>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
<class name="EmployeeInfo">
|
||||||
|
<id name="id" type="long" column="id">
|
||||||
|
<generator class="increment" />
|
||||||
|
</id>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
</hibernate-mapping>
|
Loading…
Reference in New Issue