mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-20 01:55:02 +00:00
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.LazyGroup;
|
import org.hibernate.annotations.LazyGroup;
|
||||||
import org.hibernate.annotations.Loader;
|
import org.hibernate.annotations.Loader;
|
||||||
import org.hibernate.annotations.ManyToAny;
|
import org.hibernate.annotations.ManyToAny;
|
||||||
|
import org.hibernate.annotations.OnDelete;
|
||||||
import org.hibernate.annotations.OptimisticLock;
|
import org.hibernate.annotations.OptimisticLock;
|
||||||
import org.hibernate.annotations.OrderBy;
|
import org.hibernate.annotations.OrderBy;
|
||||||
import org.hibernate.annotations.Parameter;
|
import org.hibernate.annotations.Parameter;
|
||||||
@ -480,6 +481,15 @@ public void bind() {
|
|||||||
throw new AnnotationException( message );
|
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 );
|
collection.setInverse( isMappedBy );
|
||||||
|
|
||||||
//many to many may need some second pass informations
|
//many to many may need some second pass informations
|
||||||
|
@ -293,12 +293,6 @@ public void validate(Mapping mapping) throws MappingException {
|
|||||||
assert getKey() != null : "Collection key not bound : " + getRole();
|
assert getKey() != null : "Collection key not bound : " + getRole();
|
||||||
assert getElement() != null : "Collection element 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 ) ) {
|
if ( !getKey().isValid( mapping ) ) {
|
||||||
throw new MappingException(
|
throw new MappingException(
|
||||||
"collection foreign key mapping has wrong number of columns: "
|
"collection foreign key mapping has wrong number of columns: "
|
||||||
|
@ -6,20 +6,32 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.test.annotations.onetomany;
|
package org.hibernate.test.annotations.onetomany;
|
||||||
|
|
||||||
import javax.persistence.PersistenceException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
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.Hibernate;
|
||||||
import org.hibernate.HibernateException;
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.Transaction;
|
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.exception.ConstraintViolationException;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
@ -36,6 +48,7 @@
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
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.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@ -345,6 +358,46 @@ public void testCascadeDelete() throws Exception {
|
|||||||
s.close();
|
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
|
@Test
|
||||||
public void testSimpleOneToManySet() throws Exception {
|
public void testSimpleOneToManySet() throws Exception {
|
||||||
Session s;
|
Session s;
|
||||||
@ -503,7 +556,9 @@ protected Class[] getAnnotatedClasses() {
|
|||||||
Person.class,
|
Person.class,
|
||||||
Organisation.class,
|
Organisation.class,
|
||||||
OrganisationUser.class,
|
OrganisationUser.class,
|
||||||
Model.class
|
Model.class,
|
||||||
|
OnDeleteUnidirectionalOneToManyParent.class,
|
||||||
|
OnDeleteUnidirectionalOneToManyChild.class
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,4 +566,43 @@ protected Class[] getAnnotatedClasses() {
|
|||||||
protected String[] getXmlFiles() {
|
protected String[] getXmlFiles() {
|
||||||
return new String[] { "org/hibernate/test/annotations/onetomany/orm.xml" };
|
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…
x
Reference in New Issue
Block a user