HHH-6957 : Throw TransientPropertyValueException if there are unresolved entity insert actions after persist/save/merge listeners execute
This commit is contained in:
parent
bb4738b1e4
commit
ebee6b731e
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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;
|
||||
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
/**
|
||||
* Thrown when a property cannot be persisted because it is an association
|
||||
* with a transient unsaved entity instance.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class TransientPropertyValueException extends TransientObjectException {
|
||||
private final String transientEntityName;
|
||||
private final String propertyOwnerEntityName;
|
||||
private final String propertyName;
|
||||
|
||||
/**
|
||||
* Constructs an {@link TransientPropertyValueException} instance.
|
||||
*
|
||||
* @param message - the exception message;
|
||||
* @param transientEntityName - the entity name for the transient entity
|
||||
* @param propertyOwnerEntityName - the entity name for entity that owns
|
||||
* the association property.
|
||||
* @param propertyName - the property name
|
||||
*/
|
||||
public TransientPropertyValueException(
|
||||
String message,
|
||||
String transientEntityName,
|
||||
String propertyOwnerEntityName,
|
||||
String propertyName) {
|
||||
super(message);
|
||||
this.transientEntityName = transientEntityName;
|
||||
this.propertyOwnerEntityName = propertyOwnerEntityName;
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity name for the transient entity.
|
||||
* @return the entity name for the transient entity.
|
||||
*/
|
||||
public String getTransientEntityName() {
|
||||
return transientEntityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity name for entity that owns the association
|
||||
* property.
|
||||
* @return the entity name for entity that owns the association
|
||||
* property
|
||||
*/
|
||||
public String getPropertyOwnerEntityName() {
|
||||
return propertyOwnerEntityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the property name.
|
||||
* @return the property name.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the exception message.
|
||||
* @return the exception message.
|
||||
*/
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return new StringBuilder( super.getMessage() )
|
||||
.append( ": " )
|
||||
.append( StringHelper.qualify( propertyOwnerEntityName, propertyName ) )
|
||||
.append( " -> " )
|
||||
.append( transientEntityName )
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import java.util.TreeSet;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.TransientPropertyValueException;
|
||||
import org.hibernate.engine.internal.NonNullableTransientDependencies;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
@ -131,8 +132,9 @@ public class UnresolvedEntityInsertActions {
|
|||
nonNullableTransientDependencies.getNonNullableTransientEntities().iterator().next();
|
||||
String firstPropertyPath =
|
||||
nonNullableTransientDependencies.getNonNullableTransientPropertyPaths( firstTransientDependency ).iterator().next();
|
||||
throw new PropertyValueException(
|
||||
throw new TransientPropertyValueException(
|
||||
"Not-null property references a transient value - transient instance must be saved before current operation",
|
||||
firstDependentAction.getSession().guessEntityName( firstTransientDependency ),
|
||||
firstDependentAction.getEntityName(),
|
||||
firstPropertyPath
|
||||
);
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.ReplicationMode;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.TransientPropertyValueException;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.internal.ForeignKeys;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
|
@ -377,10 +378,11 @@ public abstract class CascadingAction {
|
|||
&& 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
|
||||
throw new TransientPropertyValueException(
|
||||
"object references an unsaved transient instance - save the transient instance before flushing",
|
||||
childEntityName,
|
||||
parentEntiytName,
|
||||
propertyName
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.JDBCException;
|
|||
import org.hibernate.PropertyValueException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.TransientPropertyValueException;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
|
@ -682,7 +683,7 @@ public class MultiPathCircleCascadeTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
}
|
||||
else {
|
||||
assertTrue( ex instanceof PropertyValueException );
|
||||
assertTrue( ex instanceof TransientPropertyValueException );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
@MappedSuperclass
|
||||
public abstract class AbstractEntity implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
@Basic
|
||||
@Column(unique = true, updatable = false, length = 36, columnDefinition = "char(36)")
|
||||
private String uuid;
|
||||
@Column(updatable = false)
|
||||
private Date created;
|
||||
|
||||
public AbstractEntity() {
|
||||
super();
|
||||
uuid = UUID.randomUUID().toString();
|
||||
created = new Date();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return uuid == null ? 0 : uuid.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof AbstractEntity ))
|
||||
return false;
|
||||
final AbstractEntity other = (AbstractEntity) obj;
|
||||
if (uuid == null) {
|
||||
if (other.uuid != null)
|
||||
return false;
|
||||
} else if (!uuid.equals(other.uuid))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (id != null) {
|
||||
return "id: '" + id + "' uuid: '" + uuid + "'";
|
||||
} else {
|
||||
return "id: 'transient entity' " + " uuid: '" + uuid + "'";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
/**
|
||||
* No Documentation
|
||||
*/
|
||||
@javax.persistence.Entity
|
||||
public class B extends AbstractEntity {
|
||||
private static final long serialVersionUID = 325417243L;
|
||||
|
||||
/**
|
||||
* No documentation
|
||||
*/
|
||||
@javax.persistence.OneToMany(cascade = {
|
||||
javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH}
|
||||
, mappedBy = "b")
|
||||
private java.util.Set<G> gCollection = new java.util.HashSet<G>();
|
||||
|
||||
|
||||
/**
|
||||
* No documentation
|
||||
*/
|
||||
@javax.persistence.ManyToOne(cascade = {
|
||||
javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH}
|
||||
, optional = false)
|
||||
private C c;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* No documentation
|
||||
*/
|
||||
@javax.persistence.ManyToOne(cascade = {
|
||||
javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH}
|
||||
, optional = false)
|
||||
private D d;
|
||||
|
||||
public java.util.Set<G> getGCollection() {
|
||||
return gCollection;
|
||||
}
|
||||
|
||||
public void setGCollection(
|
||||
java.util.Set<G> parameter) {
|
||||
this.gCollection = parameter;
|
||||
}
|
||||
|
||||
public C getC() {
|
||||
return c;
|
||||
}
|
||||
|
||||
public void setC(C parameter) {
|
||||
this.c = parameter;
|
||||
}
|
||||
|
||||
public D getD() {
|
||||
return d;
|
||||
}
|
||||
|
||||
public void setD(D parameter) {
|
||||
this.d = parameter;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* No Documentation
|
||||
*/
|
||||
@javax.persistence.Entity
|
||||
public class C extends AbstractEntity {
|
||||
private static final long serialVersionUID = 1226955752L;
|
||||
|
||||
@javax.persistence.OneToMany(mappedBy = "c")
|
||||
private Set<B> bCollection = new java.util.HashSet<B>();
|
||||
|
||||
@javax.persistence.OneToMany(cascade = {
|
||||
javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH}
|
||||
, mappedBy = "c")
|
||||
private Set<D> dCollection = new java.util.HashSet<D>();
|
||||
|
||||
public Set<B> getBCollection() {
|
||||
return bCollection;
|
||||
}
|
||||
|
||||
public void setBCollection(Set<B> bCollection) {
|
||||
this.bCollection = bCollection;
|
||||
}
|
||||
|
||||
public Set<D> getDCollection() {
|
||||
return dCollection;
|
||||
}
|
||||
|
||||
public void setDCollection(Set<D> dCollection) {
|
||||
this.dCollection = dCollection;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
/**
|
||||
* No Documentation
|
||||
*/
|
||||
@javax.persistence.Entity
|
||||
public class D extends AbstractEntity {
|
||||
private static final long serialVersionUID = 2417176961L;
|
||||
|
||||
@javax.persistence.OneToMany(mappedBy = "d")
|
||||
private java.util.Set<B> bCollection = new java.util.HashSet<B>();
|
||||
|
||||
@javax.persistence.ManyToOne(optional = false)
|
||||
private C c;
|
||||
|
||||
@javax.persistence.ManyToOne(optional = false)
|
||||
private E e;
|
||||
|
||||
@javax.persistence.OneToMany(cascade = {
|
||||
javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH},
|
||||
mappedBy = "d"
|
||||
)
|
||||
private java.util.Set<F> fCollection = new java.util.HashSet<F>();
|
||||
|
||||
public java.util.Set<B> getBCollection() {
|
||||
return bCollection;
|
||||
}
|
||||
public void setBCollection(
|
||||
java.util.Set<B> parameter) {
|
||||
this.bCollection = parameter;
|
||||
}
|
||||
|
||||
public C getC() {
|
||||
return c;
|
||||
}
|
||||
public void setC(C c) {
|
||||
this.c = c;
|
||||
}
|
||||
|
||||
public E getE() {
|
||||
return e;
|
||||
}
|
||||
public void setE(E e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
public java.util.Set<F> getFCollection() {
|
||||
return fCollection;
|
||||
}
|
||||
public void setFCollection(
|
||||
java.util.Set<F> parameter) {
|
||||
this.fCollection = parameter;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
/**
|
||||
* No Documentation
|
||||
*/
|
||||
@javax.persistence.Entity
|
||||
public class E extends AbstractEntity {
|
||||
private static final long serialVersionUID = 1226955558L;
|
||||
|
||||
@javax.persistence.OneToMany(mappedBy = "e")
|
||||
private java.util.Set<D> dCollection = new java.util.HashSet<D>();
|
||||
|
||||
@javax.persistence.ManyToOne(optional = true)
|
||||
private F f;
|
||||
|
||||
public java.util.Set<D> getDCollection() {
|
||||
return dCollection;
|
||||
}
|
||||
public void setDCollection(java.util.Set<D> dCollection) {
|
||||
this.dCollection = dCollection;
|
||||
}
|
||||
|
||||
public F getF() {
|
||||
return f;
|
||||
}
|
||||
public void setF(F parameter) {
|
||||
this.f = parameter;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
/**
|
||||
* No Documentation
|
||||
*/
|
||||
@javax.persistence.Entity
|
||||
public class F extends AbstractEntity {
|
||||
private static final long serialVersionUID = 1471534025L;
|
||||
|
||||
/**
|
||||
* No documentation
|
||||
*/
|
||||
@javax.persistence.OneToMany(cascade = {
|
||||
javax.persistence.CascadeType.MERGE, javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REFRESH}
|
||||
, mappedBy = "f")
|
||||
private java.util.Set<E> eCollection = new java.util.HashSet<E>();
|
||||
|
||||
@javax.persistence.ManyToOne(optional = false)
|
||||
private D d;
|
||||
|
||||
@javax.persistence.ManyToOne(optional = false)
|
||||
private G g;
|
||||
|
||||
public java.util.Set<E> getECollection() {
|
||||
return eCollection;
|
||||
}
|
||||
public void setECollection(
|
||||
java.util.Set<E> parameter) {
|
||||
this.eCollection = parameter;
|
||||
}
|
||||
|
||||
public D getD() {
|
||||
return d;
|
||||
}
|
||||
public void setD(D parameter) {
|
||||
this.d = parameter;
|
||||
}
|
||||
|
||||
public G getG() {
|
||||
return g;
|
||||
}
|
||||
public void setG(G parameter) {
|
||||
this.g = parameter;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
/**
|
||||
* No Documentation
|
||||
*/
|
||||
@javax.persistence.Entity
|
||||
public class G extends AbstractEntity {
|
||||
private static final long serialVersionUID = 325417437L;
|
||||
|
||||
@javax.persistence.ManyToOne(optional = false)
|
||||
private B b;
|
||||
|
||||
@javax.persistence.OneToMany(mappedBy = "g")
|
||||
private java.util.Set<F> fCollection = new java.util.HashSet<F>();
|
||||
|
||||
public B getB() {
|
||||
return b;
|
||||
}
|
||||
public void setB(B parameter){
|
||||
this.b = parameter;
|
||||
}
|
||||
|
||||
public java.util.Set<F> getFCollection() {
|
||||
return fCollection;
|
||||
}
|
||||
public void setFCollection(
|
||||
java.util.Set<F> parameter) {
|
||||
this.fCollection = parameter;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, 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.ejb.test.cascade.multicircle;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.RollbackException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.hibernate.TransientPropertyValueException;
|
||||
import org.hibernate.ejb.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
|
||||
/**
|
||||
* This test uses a complicated model that requires Hibernate to delay
|
||||
* inserts until non-nullable transient entity dependencies are resolved.
|
||||
*
|
||||
* All IDs are generated from a sequence.
|
||||
*
|
||||
* JPA cascade types are used (javax.persistence.CascadeType)..
|
||||
*
|
||||
* This test uses the following model:
|
||||
*
|
||||
* <code>
|
||||
* ------------------------------ N G
|
||||
* |
|
||||
* | 1
|
||||
* | |
|
||||
* | |
|
||||
* | N
|
||||
* |
|
||||
* | E N--------------0,1 * F
|
||||
* |
|
||||
* | 1 N
|
||||
* | | |
|
||||
* | | |
|
||||
* 1 N |
|
||||
* * |
|
||||
* B * N---1 D * 1------------------
|
||||
* *
|
||||
* N N
|
||||
* | |
|
||||
* | |
|
||||
* 1 |
|
||||
* |
|
||||
* C * 1-----
|
||||
*</code>
|
||||
*
|
||||
* In the diagram, all associations are bidirectional;
|
||||
* assocations marked with '*' cascade persist, save, merge operations to the
|
||||
* associated entities (e.g., B cascades persist to D, but D does not cascade
|
||||
* persist to B);
|
||||
*
|
||||
* b, c, d, e, f, and g are all transient unsaved that are associated with each other.
|
||||
*
|
||||
* When saving b, the entities are added to the ActionQueue in the following order:
|
||||
* c, d (depends on e), f (depends on d, g), e, b, g.
|
||||
*
|
||||
* Entities are inserted in the following order:
|
||||
* c, e, d, b, g, f.
|
||||
*/
|
||||
public class MultiCircleJpaCascadeTest extends BaseEntityManagerFunctionalTestCase {
|
||||
private B b;
|
||||
private C c;
|
||||
private D d;
|
||||
private E e;
|
||||
private F f;
|
||||
private G g;
|
||||
private boolean skipCleanup;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
b = new B();
|
||||
c = new C();
|
||||
d = new D();
|
||||
e = new E();
|
||||
f = new F();
|
||||
g = new G();
|
||||
|
||||
b.getGCollection().add( g );
|
||||
b.setC( c );
|
||||
b.setD( d );
|
||||
|
||||
c.getBCollection().add( b );
|
||||
c.getDCollection().add( d );
|
||||
|
||||
d.getBCollection().add( b );
|
||||
d.setC( c );
|
||||
d.setE( e );
|
||||
d.getFCollection().add( f );
|
||||
|
||||
e.getDCollection().add( d );
|
||||
e.setF( f );
|
||||
|
||||
f.getECollection().add( e );
|
||||
f.setD( d );
|
||||
f.setG( g );
|
||||
|
||||
g.setB( b );
|
||||
g.getFCollection().add( f );
|
||||
|
||||
skipCleanup = false;
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if ( ! skipCleanup ) {
|
||||
b.setC( null );
|
||||
b.setD( null );
|
||||
b.getGCollection().remove( g );
|
||||
|
||||
c.getBCollection().remove( b );
|
||||
c.getDCollection().remove( d );
|
||||
|
||||
d.getBCollection().remove( b );
|
||||
d.setC( null );
|
||||
d.setE( null );
|
||||
d.getFCollection().remove( f );
|
||||
|
||||
e.getDCollection().remove( d );
|
||||
e.setF( null );
|
||||
|
||||
f.setD( null );
|
||||
f.getECollection().remove( e );
|
||||
f.setG( null );
|
||||
|
||||
g.setB( null );
|
||||
g.getFCollection().remove( f );
|
||||
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
b = em.merge( b );
|
||||
c = em.merge( c );
|
||||
d = em.merge( d );
|
||||
e = em.merge( e );
|
||||
f = em.merge( f );
|
||||
g = em.merge( g );
|
||||
em.remove( f );
|
||||
em.remove( g );
|
||||
em.remove( b );
|
||||
em.remove( d );
|
||||
em.remove( e );
|
||||
em.remove( c );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersist() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.persist( b );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistNoCascadeToTransient() {
|
||||
skipCleanup = true;
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
try {
|
||||
em.persist( c );
|
||||
fail( "should have failed." );
|
||||
}
|
||||
catch( IllegalStateException ex ) {
|
||||
assertTrue( TransientPropertyValueException.class.isInstance( ex.getCause() ) );
|
||||
TransientPropertyValueException pve = (TransientPropertyValueException) ex.getCause();
|
||||
assertEquals( G.class.getName(), pve.getTransientEntityName() );
|
||||
assertEquals( F.class.getName(), pve.getPropertyOwnerEntityName() );
|
||||
assertEquals( "g", pve.getPropertyName() );
|
||||
}
|
||||
em.getTransaction().rollback();
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-6999" )
|
||||
// fails on d.e; should pass
|
||||
public void testPersistThenUpdate() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.persist( b );
|
||||
// remove old e from associations
|
||||
e.getDCollection().remove( d );
|
||||
d.setE( null );
|
||||
f.getECollection().remove( e );
|
||||
e.setF( null );
|
||||
// add new e to associations
|
||||
e = new E();
|
||||
e.getDCollection().add( d );
|
||||
f.getECollection().add( e );
|
||||
d.setE( e );
|
||||
e.setF( f );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersistThenUpdateNoCascadeToTransient() {
|
||||
// expected to fail, so nothing will be persisted.
|
||||
skipCleanup = true;
|
||||
|
||||
// remove elements from collections and persist
|
||||
c.getBCollection().clear();
|
||||
c.getDCollection().clear();
|
||||
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.persist( c );
|
||||
// now add the elements back
|
||||
c.getBCollection().add( b );
|
||||
c.getDCollection().add( d );
|
||||
try {
|
||||
em.getTransaction().commit();
|
||||
fail( "should have thrown IllegalStateException");
|
||||
}
|
||||
catch ( RollbackException ex ) {
|
||||
assertTrue( ex.getCause() instanceof IllegalStateException );
|
||||
IllegalStateException ise = ( IllegalStateException ) ex.getCause();
|
||||
// should fail on entity g (due to no cascade to f.g);
|
||||
// instead it fails on entity e ( due to no cascade to d.e)
|
||||
// because e is not in the process of being saved yet.
|
||||
// when HHH-6999 is fixed, this test should be changed to
|
||||
// check for g and f.g
|
||||
assertTrue( ise.getCause() instanceof TransientPropertyValueException );
|
||||
TransientPropertyValueException tpve = ( TransientPropertyValueException ) ise.getCause();
|
||||
assertEquals( E.class.getName(), tpve.getTransientEntityName() );
|
||||
assertEquals( D.class.getName(), tpve.getPropertyOwnerEntityName() );
|
||||
assertEquals( "e", tpve.getPropertyName() );
|
||||
}
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
b = em.merge( b );
|
||||
c = b.getC();
|
||||
d = b.getD();
|
||||
e = d.getE();
|
||||
f = e.getF();
|
||||
g = f.getG();
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
private void check() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
B bRead = em.find( B.class, b.getId() );
|
||||
Assert.assertEquals( b, bRead );
|
||||
|
||||
G gRead = bRead.getGCollection().iterator().next();
|
||||
Assert.assertEquals( g, gRead );
|
||||
C cRead = bRead.getC();
|
||||
Assert.assertEquals( c, cRead );
|
||||
D dRead = bRead.getD();
|
||||
Assert.assertEquals( d, dRead );
|
||||
|
||||
Assert.assertSame( bRead, cRead.getBCollection().iterator().next() );
|
||||
Assert.assertSame( dRead, cRead.getDCollection().iterator().next() );
|
||||
|
||||
Assert.assertSame( bRead, dRead.getBCollection().iterator().next() );
|
||||
Assert.assertEquals( cRead, dRead.getC() );
|
||||
E eRead = dRead.getE();
|
||||
Assert.assertEquals( e, eRead );
|
||||
F fRead = dRead.getFCollection().iterator().next();
|
||||
Assert.assertEquals( f, fRead );
|
||||
|
||||
Assert.assertSame( dRead, eRead.getDCollection().iterator().next() );
|
||||
Assert.assertSame( fRead, eRead.getF() );
|
||||
|
||||
Assert.assertSame( eRead, fRead.getECollection().iterator().next() );
|
||||
Assert.assertSame( dRead, fRead.getD() );
|
||||
Assert.assertSame( gRead, fRead.getG());
|
||||
|
||||
Assert.assertSame( bRead, gRead.getB() );
|
||||
Assert.assertSame( fRead, gRead.getFCollection().iterator().next() );
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class[] getAnnotatedClasses() {
|
||||
return new Class[]{
|
||||
B.class,
|
||||
C.class,
|
||||
D.class,
|
||||
E.class,
|
||||
F.class,
|
||||
G.class
|
||||
};
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue