HHH-6382: Allow to use @OnDelete annotation on unidirectional @OneToMany associations

This commit is contained in:
Alexey Nesterov 2017-08-12 10:17:39 +01:00 committed by Vlad Mihalcea
parent 1392b43852
commit 7c2a588613
3 changed files with 107 additions and 9 deletions

View File

@ -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

View File

@ -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: "

View File

@ -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;
}
}