|
From: <hib...@li...> - 2006-06-27 21:23:31
|
Author: ste...@jb...
Date: 2006-06-27 17:22:42 -0400 (Tue, 27 Jun 2006)
New Revision: 10057
Modified:
trunk/Hibernate3/src/org/hibernate/engine/Cascade.java
trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java
trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java
Log:
HHH-1822 : persist() and transient, non-cascaded associations
Modified: trunk/Hibernate3/src/org/hibernate/engine/Cascade.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/engine/Cascade.java 2006-06-27 21:20:52 UTC (rev 10056)
+++ trunk/Hibernate3/src/org/hibernate/engine/Cascade.java 2006-06-27 21:22:42 UTC (rev 10057)
@@ -232,7 +232,7 @@
final Object anything)
throws HibernateException {
- if ( persister.hasCascades() ) { // performance opt
+ if ( persister.hasCascades() || action.requiresNoCascadeChecking() ) { // performance opt
if ( log.isTraceEnabled() ) {
log.trace( "processing cascade " + action + " for: " + persister.getEntityName() );
}
@@ -253,6 +253,15 @@
false
);
}
+ else {
+ action.noCascade(
+ eventSource,
+ persister.getPropertyValue( parent, i, eventSource.getEntityMode() ),
+ parent,
+ persister,
+ i
+ );
+ }
}
if ( log.isTraceEnabled() ) {
Modified: trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java 2006-06-27 21:20:52 UTC (rev 10056)
+++ trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java 2006-06-27 21:22:42 UTC (rev 10057)
@@ -10,9 +10,13 @@
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.ReplicationMode;
+import org.hibernate.TransientObjectException;
+import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.event.EventSource;
import org.hibernate.type.CollectionType;
+import org.hibernate.type.Type;
+import org.hibernate.type.EntityType;
/**
* A session action that may be cascaded from parent entity to its children
@@ -20,13 +24,13 @@
* @author Gavin King
*/
public abstract class CascadingAction {
-
+
private static final Log log = LogFactory.getLog(CascadingAction.class);
/**
* cascade the action to the child object
*/
- public abstract void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public abstract void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException;
/**
* Should this action be cascaded to the given (possibly uninitialized) collection?
@@ -41,7 +45,7 @@
* @see org.hibernate.Session#delete(Object)
*/
public static final CascadingAction DELETE = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
if ( log.isTraceEnabled() ) {
log.trace("cascading to delete: " + entityName);
@@ -60,14 +64,16 @@
return "ACTION_DELETE";
}
};
-
+
/**
* @see org.hibernate.Session#lock(Object, LockMode)
*/
public static final CascadingAction LOCK = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to lock: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to lock: " + entityName );
+ }
session.lock( entityName, child, LockMode.NONE/*(LockMode) anything*/ );
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -82,14 +88,16 @@
return "ACTION_LOCK";
}
};
-
+
/**
* @see org.hibernate.Session#refresh(Object)
*/
public static final CascadingAction REFRESH = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to refresh: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to refresh: " + entityName );
+ }
session.refresh( child, (Map) anything );
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -103,14 +111,16 @@
return "ACTION_REFRESH";
}
};
-
+
/**
* @see org.hibernate.Session#evict(Object)
*/
public static final CascadingAction EVICT = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to evict: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to evict: " + entityName );
+ }
session.evict(child);
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -124,14 +134,16 @@
return "ACTION_EVICT";
}
};
-
+
/**
* @see org.hibernate.Session#saveOrUpdate(Object)
*/
public static final CascadingAction SAVE_UPDATE = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to saveOrUpdate: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to saveOrUpdate: " + entityName );
+ }
session.saveOrUpdate(entityName, child);
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -146,14 +158,16 @@
return "ACTION_SAVE_UPDATE";
}
};
-
+
/**
* @see org.hibernate.Session#merge(Object)
*/
public static final CascadingAction MERGE = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to merge: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to merge: " + entityName );
+ }
session.merge( entityName, child, (Map) anything );
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -169,15 +183,17 @@
return "ACTION_MERGE";
}
};
-
+
/**
* @see org.hibernate.classic.Session#saveOrUpdateCopy(Object)
*/
public static final CascadingAction SAVE_UPDATE_COPY = new CascadingAction() {
// for deprecated saveOrUpdateCopy()
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to saveOrUpdateCopy: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to saveOrUpdateCopy: " + entityName );
+ }
session.saveOrUpdateCopy( entityName, child, (Map) anything );
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -192,14 +208,16 @@
return "ACTION_SAVE_UPDATE_COPY";
}
};
-
+
/**
* @see org.hibernate.Session#persist(Object)
*/
public static final CascadingAction PERSIST = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to persist: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to persist: " + entityName );
+ }
session.persist( entityName, child, (Map) anything );
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -222,7 +240,9 @@
public static final CascadingAction PERSIST_ON_FLUSH = new CascadingAction() {
public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to persistOnFlush: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to persistOnFlush: " + entityName );
+ }
session.persistOnFlush( entityName, child, (Map) anything );
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -232,18 +252,48 @@
public boolean deleteOrphans() {
return true;
}
+ public boolean requiresNoCascadeChecking() {
+ return true;
+ }
+ public void noCascade(
+ EventSource session,
+ Object child,
+ Object parent,
+ EntityPersister persister,
+ int propertyIndex) {
+ if ( child == null ) {
+ return;
+ }
+ Type type = persister.getPropertyTypes()[propertyIndex];
+ if ( type.isEntityType() ) {
+ String childEntityName = ( ( EntityType ) type ).getAssociatedEntityName( session.getFactory() );
+ if ( ForeignKeys.isTransient( childEntityName, child, null, session ) ) {
+ String parentEntiytName = persister.getEntityName();
+ String propertyName = persister.getPropertyNames()[propertyIndex];
+ throw new TransientObjectException(
+ "object references an unsaved transient instance - " +
+ "save the transient instance before flushing: " +
+ parentEntiytName + "." + propertyName + " -> " + childEntityName
+ );
+
+ }
+ }
+ }
+
public String toString() {
return "ACTION_PERSIST_ON_FLUSH";
}
};
-
+
/**
* @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
*/
public static final CascadingAction REPLICATE = new CascadingAction() {
- public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
+ public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
throws HibernateException {
- if ( log.isTraceEnabled() ) log.trace("cascading to replicate: " + entityName);
+ if ( log.isTraceEnabled() ) {
+ log.trace( "cascading to replicate: " + entityName );
+ }
session.replicate( entityName, child, (ReplicationMode) anything );
}
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
@@ -257,9 +307,17 @@
return "ACTION_REPLICATE";
}
};
-
+
CascadingAction() {}
+ public boolean requiresNoCascadeChecking() {
+ return false;
+ }
+
+
+ public void noCascade(EventSource session, Object child, Object parent, EntityPersister persister, int propertyIndex) {
+ }
+
/**
* Iterate all the collection elements, loading them from the database if necessary.
*/
@@ -281,7 +339,7 @@
return ( (PersistentCollection) collection ).queuedAdditionIterator();
}
}
-
+
private static boolean collectionIsInitialized(Object collection) {
return !(collection instanceof PersistentCollection) || ( (PersistentCollection) collection ).wasInitialized();
}
Modified: trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java
===================================================================
--- trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java 2006-06-27 21:20:52 UTC (rev 10056)
+++ trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java 2006-06-27 21:22:42 UTC (rev 10057)
@@ -215,7 +215,7 @@
// context-entity-identifier returns null explicitly if the entity
// is not associated with the persistence context; so make some
// deeper checks...
- if ( isTransient(entityName, object, null, session) ) {
+ if ( isTransient(entityName, object, Boolean.FALSE, session) ) {
throw new TransientObjectException(
"object references an unsaved transient instance - save the transient instance before flushing: " +
entityName == null ? session.guessEntityName( object ) : entityName
|