HHH-7072 force recreation of element collections of components with all
nullable properties Conflicts: hibernate-core/src/main/java/org/hibernate/type/ComponentType.java hibernate-core/src/test/java/org/hibernate/test/annotations/collectionelement/embeddables/withcustomenumdef/Location.java
This commit is contained in:
parent
d22c60cc68
commit
677ac13458
|
@ -53,6 +53,7 @@ import org.hibernate.internal.util.collections.IdentitySet;
|
|||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -660,6 +661,18 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
|
|||
* Do we need to completely recreate this collection when it changes?
|
||||
*/
|
||||
public boolean needsRecreate(CollectionPersister persister) {
|
||||
// Workaround for situations like HHH-7072. If the collection element is a component that consists entirely
|
||||
// of nullable properties, we currently have to forcefully recreate the entire collection. See the use
|
||||
// of hasNotNullableColumns in the AbstractCollectionPersister constructor for more info. In order to delete
|
||||
// row-by-row, that would require SQL like "WHERE ( COL = ? OR ( COL is null AND ? is null ) )", rather than
|
||||
// the current "WHERE COL = ?" (fails for null for most DBs). Note that
|
||||
// the param would have to be bound twice. Until we eventually add "parameter bind points" concepts to the
|
||||
// AST in ORM 5+, handling this type of condition is either extremely difficult or impossible. Forcing
|
||||
// recreation isn't ideal, but not really any other option in ORM 4.
|
||||
if (persister.getElementType() instanceof ComponentType) {
|
||||
ComponentType componentType = (ComponentType) persister.getElementType();
|
||||
return !componentType.hasNotNullProperty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ public class ComponentType extends AbstractType implements CompositeType {
|
|||
private final CascadeStyle[] cascade;
|
||||
private final FetchMode[] joinedFetch;
|
||||
private final boolean isKey;
|
||||
private boolean hasNotNullProperty;
|
||||
|
||||
protected final EntityMode entityMode;
|
||||
protected final ComponentTuplizer componentTuplizer;
|
||||
|
@ -87,6 +88,9 @@ public class ComponentType extends AbstractType implements CompositeType {
|
|||
this.propertyNullability[i] = prop.isNullable();
|
||||
this.cascade[i] = prop.getCascadeStyle();
|
||||
this.joinedFetch[i] = prop.getFetchMode();
|
||||
if (!prop.isNullable()) {
|
||||
hasNotNullProperty = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.entityMode = metamodel.getEntityMode();
|
||||
|
@ -723,4 +727,8 @@ public class ComponentType extends AbstractType implements CompositeType {
|
|||
"Unable to locate property named " + name + " on " + getReturnedClass().getName()
|
||||
);
|
||||
}
|
||||
|
||||
public boolean hasNotNullProperty() {
|
||||
return hasNotNullProperty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,4 +69,25 @@ public class Location {
|
|||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (! obj.getClass().equals( Location.class )) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Location loc = (Location) obj;
|
||||
if (name != null ? !name.equals(loc.name) : loc.name != null) return false;
|
||||
if (type != null ? !type.equals(loc.type) : loc.type != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = (name != null ? name.hashCode() : 0);
|
||||
result = 31 * result + (type != null ? type.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,14 @@
|
|||
*/
|
||||
package org.hibernate.test.annotations.collectionelement.embeddables.withcustomenumdef;
|
||||
|
||||
import org.junit.Test;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -57,4 +59,41 @@ public class TestBasicOps extends BaseCoreFunctionalTestCase {
|
|||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-7072")
|
||||
public void testEmbeddableWithNullables() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
Query q = new Query( new Location( null, Location.Type.COMMUNE ) );
|
||||
s.save( q );
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
s.beginTransaction();
|
||||
q.getIncludedLocations().add( new Location( null, Location.Type.COUNTY ) );
|
||||
s.update( q );
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
s.beginTransaction();
|
||||
q = (Query) s.get( Query.class, q.getId() );
|
||||
// assertEquals( 2, q.getIncludedLocations().size() );
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
s.beginTransaction();
|
||||
Iterator<Location> itr = q.getIncludedLocations().iterator();
|
||||
itr.next();
|
||||
itr.remove();
|
||||
s.update( q );
|
||||
s.getTransaction().commit();
|
||||
s.clear();
|
||||
|
||||
s.beginTransaction();
|
||||
q = (Query) s.get( Query.class, q.getId() );
|
||||
assertEquals( 1, q.getIncludedLocations().size() );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue