HHH-6382: Allow to use @OnDelete annotation on unidirectional @OneToMany associations
This commit is contained in:
parent
1392b43852
commit
7c2a588613
|
@ -46,6 +46,7 @@ import org.hibernate.annotations.LazyCollectionOption;
|
|||
import org.hibernate.annotations.LazyGroup;
|
||||
import org.hibernate.annotations.Loader;
|
||||
import org.hibernate.annotations.ManyToAny;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OptimisticLock;
|
||||
import org.hibernate.annotations.OrderBy;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
@ -480,6 +481,15 @@ public abstract class CollectionBinder {
|
|||
throw new AnnotationException( message );
|
||||
}
|
||||
|
||||
if (!isMappedBy
|
||||
&& oneToMany
|
||||
&& property.isAnnotationPresent( OnDelete.class )
|
||||
&& !property.isAnnotationPresent( JoinColumn.class )) {
|
||||
String message = "Unidirectional one-to-many associations annotated with @OnDelete must define @JoinColumn: ";
|
||||
message += StringHelper.qualify( propertyHolder.getPath(), propertyName );
|
||||
throw new AnnotationException( message );
|
||||
}
|
||||
|
||||
collection.setInverse( isMappedBy );
|
||||
|
||||
//many to many may need some second pass informations
|
||||
|
|
|
@ -293,12 +293,6 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
assert getKey() != null : "Collection key not bound : " + getRole();
|
||||
assert getElement() != null : "Collection element not bound : " + getRole();
|
||||
|
||||
if ( getKey().isCascadeDeleteEnabled() && ( !isInverse() || !isOneToMany() ) ) {
|
||||
throw new MappingException(
|
||||
"only inverse one-to-many associations may use on-delete=\"cascade\": "
|
||||
+ getRole()
|
||||
);
|
||||
}
|
||||
if ( !getKey().isValid( mapping ) ) {
|
||||
throw new MappingException(
|
||||
"collection foreign key mapping has wrong number of columns: "
|
||||
|
|
|
@ -6,20 +6,32 @@
|
|||
*/
|
||||
package org.hibernate.test.annotations.onetomany;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
|
@ -36,6 +48,7 @@ import org.junit.Assert;
|
|||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
@ -345,6 +358,46 @@ public class OneToManyTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCascadeDeleteWithUnidirectionalAssociation() throws Exception {
|
||||
OnDeleteUnidirectionalOneToManyChild child = new OnDeleteUnidirectionalOneToManyChild();
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
OnDeleteUnidirectionalOneToManyParent parent = new OnDeleteUnidirectionalOneToManyParent();
|
||||
parent.children = Collections.singletonList( child);
|
||||
session.persist( parent );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
session.createQuery("delete from OnDeleteUnidirectionalOneToManyParent").executeUpdate();
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
OnDeleteUnidirectionalOneToManyChild e1 = session.get( OnDeleteUnidirectionalOneToManyChild.class, child.id );
|
||||
assertNull( "delete cascade should work", e1 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnDeleteWithoutJoinColumn() throws Exception {
|
||||
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
|
||||
.build();
|
||||
|
||||
try {
|
||||
new MetadataSources( serviceRegistry )
|
||||
.addAnnotatedClass( OnDeleteUnidirectionalOneToMany.class )
|
||||
.addAnnotatedClass( ParentUnawareChild.class )
|
||||
.getMetadataBuilder()
|
||||
.build();
|
||||
}
|
||||
catch ( AnnotationException e ) {
|
||||
assertTrue(e.getMessage().contains( "Unidirectional one-to-many associations annotated with @OnDelete must define @JoinColumn" ));
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( serviceRegistry );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOneToManySet() throws Exception {
|
||||
Session s;
|
||||
|
@ -503,7 +556,9 @@ public class OneToManyTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
Person.class,
|
||||
Organisation.class,
|
||||
OrganisationUser.class,
|
||||
Model.class
|
||||
Model.class,
|
||||
OnDeleteUnidirectionalOneToManyParent.class,
|
||||
OnDeleteUnidirectionalOneToManyChild.class
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -511,4 +566,43 @@ public class OneToManyTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
protected String[] getXmlFiles() {
|
||||
return new String[] { "org/hibernate/test/annotations/onetomany/orm.xml" };
|
||||
}
|
||||
|
||||
@Entity(name = "OnDeleteUnidirectionalOneToManyParent")
|
||||
public static class OnDeleteUnidirectionalOneToManyParent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "a_id")
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
List<OnDeleteUnidirectionalOneToManyChild> children;
|
||||
}
|
||||
|
||||
@Entity(name = "OnDeleteUnidirectionalOneToManyChild")
|
||||
public static class OnDeleteUnidirectionalOneToManyChild {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
}
|
||||
|
||||
@Entity(name = "OnDeleteUnidirectionalOneToMany")
|
||||
public static class OnDeleteUnidirectionalOneToMany {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@OnDelete(action = OnDeleteAction.CASCADE)
|
||||
List<ParentUnawareChild> children;
|
||||
}
|
||||
|
||||
@Entity(name = "ParentUnawareChild")
|
||||
public static class ParentUnawareChild {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue