HHH-7610 Add an option to initialize empty components when all the properties are null
Note that this commit also changes the semantic of the comparison between a null component and a component with all properties null: they are considered equivalent.
This commit is contained in:
parent
701f59b132
commit
d71f931429
|
@ -1009,4 +1009,13 @@ public interface AvailableSettings {
|
||||||
* Values are {@code true} (pass the NULLs) or {@code false} (do not pass the NULLs).
|
* Values are {@code true} (pass the NULLs) or {@code false} (do not pass the NULLs).
|
||||||
*/
|
*/
|
||||||
String PROCEDURE_NULL_PARAM_PASSING = "hibernate.proc.param_null_passing";
|
String PROCEDURE_NULL_PARAM_PASSING = "hibernate.proc.param_null_passing";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable instantiation of composite/embedded objects when all of its attribute values are {@code null}.
|
||||||
|
* The default (and historical) behavior is that a {@code null} reference will be used to represent the
|
||||||
|
* composite when all of its attributes are {@code null}
|
||||||
|
*
|
||||||
|
* @since 5.1
|
||||||
|
*/
|
||||||
|
String CREATE_EMPTY_COMPOSITES_ENABLED = "hibernate.create_empty_composites.enabled";
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,9 @@ import java.util.Map;
|
||||||
import org.hibernate.EntityMode;
|
import org.hibernate.EntityMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.boot.spi.MetadataBuildingOptions;
|
import org.hibernate.boot.spi.MetadataBuildingOptions;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||||
|
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
import org.hibernate.tuple.PropertyFactory;
|
import org.hibernate.tuple.PropertyFactory;
|
||||||
|
@ -39,6 +42,7 @@ public class ComponentMetamodel implements Serializable {
|
||||||
// cached for efficiency...
|
// cached for efficiency...
|
||||||
private final int propertySpan;
|
private final int propertySpan;
|
||||||
private final Map propertyIndexes = new HashMap();
|
private final Map propertyIndexes = new HashMap();
|
||||||
|
private final boolean createEmptyCompositesEnabled;
|
||||||
|
|
||||||
// public ComponentMetamodel(Component component, SessionFactoryImplementor sessionFactory) {
|
// public ComponentMetamodel(Component component, SessionFactoryImplementor sessionFactory) {
|
||||||
public ComponentMetamodel(Component component, MetadataBuildingOptions metadataBuildingOptions) {
|
public ComponentMetamodel(Component component, MetadataBuildingOptions metadataBuildingOptions) {
|
||||||
|
@ -65,6 +69,15 @@ public class ComponentMetamodel implements Serializable {
|
||||||
entityMode,
|
entityMode,
|
||||||
component
|
component
|
||||||
) : componentTuplizerFactory.constructTuplizer( tuplizerClassName, component );
|
) : componentTuplizerFactory.constructTuplizer( tuplizerClassName, component );
|
||||||
|
|
||||||
|
final ConfigurationService cs = component.getMetadata().getMetadataBuildingOptions().getServiceRegistry()
|
||||||
|
.getService(ConfigurationService.class);
|
||||||
|
|
||||||
|
this.createEmptyCompositesEnabled = ConfigurationHelper.getBoolean(
|
||||||
|
Environment.CREATE_EMPTY_COMPOSITES_ENABLED,
|
||||||
|
cs.getSettings(),
|
||||||
|
false
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isKey() {
|
public boolean isKey() {
|
||||||
|
@ -106,4 +119,8 @@ public class ComponentMetamodel implements Serializable {
|
||||||
return componentTuplizer;
|
return componentTuplizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCreateEmptyCompositesEnabled() {
|
||||||
|
return createEmptyCompositesEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
private final FetchMode[] joinedFetch;
|
private final FetchMode[] joinedFetch;
|
||||||
private final boolean isKey;
|
private final boolean isKey;
|
||||||
private boolean hasNotNullProperty;
|
private boolean hasNotNullProperty;
|
||||||
|
private final boolean createEmptyCompositesEnabled;
|
||||||
|
|
||||||
protected final EntityMode entityMode;
|
protected final EntityMode entityMode;
|
||||||
protected final ComponentTuplizer componentTuplizer;
|
protected final ComponentTuplizer componentTuplizer;
|
||||||
|
@ -80,6 +81,7 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
|
|
||||||
this.entityMode = metamodel.getEntityMode();
|
this.entityMode = metamodel.getEntityMode();
|
||||||
this.componentTuplizer = metamodel.getComponentTuplizer();
|
this.componentTuplizer = metamodel.getComponentTuplizer();
|
||||||
|
this.createEmptyCompositesEnabled = metamodel.isCreateEmptyCompositesEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isKey() {
|
public boolean isKey() {
|
||||||
|
@ -158,9 +160,7 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
if ( x == y ) {
|
if ( x == y ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( x == null || y == null ) {
|
// null value and empty component are considered equivalent
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Object[] xvalues = getPropertyValues( x, entityMode );
|
Object[] xvalues = getPropertyValues( x, entityMode );
|
||||||
Object[] yvalues = getPropertyValues( y, entityMode );
|
Object[] yvalues = getPropertyValues( y, entityMode );
|
||||||
for ( int i = 0; i < propertySpan; i++ ) {
|
for ( int i = 0; i < propertySpan; i++ ) {
|
||||||
|
@ -176,9 +176,7 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
if ( x == y ) {
|
if ( x == y ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( x == null || y == null ) {
|
// null value and empty component are considered equivalent
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for ( int i = 0; i < propertySpan; i++ ) {
|
for ( int i = 0; i < propertySpan; i++ ) {
|
||||||
if ( !propertyTypes[i].isEqual( getPropertyValue( x, i ), getPropertyValue( y, i ) ) ) {
|
if ( !propertyTypes[i].isEqual( getPropertyValue( x, i ), getPropertyValue( y, i ) ) ) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -193,9 +191,7 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
if ( x == y ) {
|
if ( x == y ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ( x == null || y == null ) {
|
// null value and empty component are considered equivalent
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for ( int i = 0; i < propertySpan; i++ ) {
|
for ( int i = 0; i < propertySpan; i++ ) {
|
||||||
if ( !propertyTypes[i].isEqual( getPropertyValue( x, i ), getPropertyValue( y, i ), factory ) ) {
|
if ( !propertyTypes[i].isEqual( getPropertyValue( x, i ), getPropertyValue( y, i ), factory ) ) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -253,9 +249,7 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
if ( x == y ) {
|
if ( x == y ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( x == null || y == null ) {
|
// null value and empty component are considered equivalent
|
||||||
return true;
|
|
||||||
}
|
|
||||||
for ( int i = 0; i < propertySpan; i++ ) {
|
for ( int i = 0; i < propertySpan; i++ ) {
|
||||||
if ( propertyTypes[i].isDirty( getPropertyValue( x, i ), getPropertyValue( y, i ), session ) ) {
|
if ( propertyTypes[i].isDirty( getPropertyValue( x, i ), getPropertyValue( y, i ), session ) ) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -269,9 +263,7 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
if ( x == y ) {
|
if ( x == y ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( x == null || y == null ) {
|
// null value and empty component are considered equivalent
|
||||||
return true;
|
|
||||||
}
|
|
||||||
int loc = 0;
|
int loc = 0;
|
||||||
for ( int i = 0; i < propertySpan; i++ ) {
|
for ( int i = 0; i < propertySpan; i++ ) {
|
||||||
int len = propertyTypes[i].getColumnSpan( session.getFactory() );
|
int len = propertyTypes[i].getColumnSpan( session.getFactory() );
|
||||||
|
@ -408,6 +400,9 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
|
|
||||||
public Object getPropertyValue(Object component, int i)
|
public Object getPropertyValue(Object component, int i)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
|
if (component == null) {
|
||||||
|
component = new Object[propertySpan];
|
||||||
|
}
|
||||||
if ( component instanceof Object[] ) {
|
if ( component instanceof Object[] ) {
|
||||||
// A few calls to hashCode pass the property values already in an
|
// A few calls to hashCode pass the property values already in an
|
||||||
// Object[] (ex: QueryKey hash codes for cached queries).
|
// Object[] (ex: QueryKey hash codes for cached queries).
|
||||||
|
@ -429,6 +424,9 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
@Override
|
@Override
|
||||||
public Object[] getPropertyValues(Object component, EntityMode entityMode)
|
public Object[] getPropertyValues(Object component, EntityMode entityMode)
|
||||||
throws HibernateException {
|
throws HibernateException {
|
||||||
|
if (component == null) {
|
||||||
|
component = new Object[propertySpan];
|
||||||
|
}
|
||||||
if ( component instanceof Object[] ) {
|
if ( component instanceof Object[] ) {
|
||||||
// A few calls to hashCode pass the property values already in an
|
// A few calls to hashCode pass the property values already in an
|
||||||
// Object[] (ex: QueryKey hash codes for cached queries).
|
// Object[] (ex: QueryKey hash codes for cached queries).
|
||||||
|
@ -689,6 +687,9 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
setPropertyValues( result, resolvedValues, entityMode );
|
setPropertyValues( result, resolvedValues, entityMode );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
else if ( isCreateEmptyCompositesEnabled() ) {
|
||||||
|
return instantiate( owner, session );
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -827,4 +828,8 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
|
||||||
public boolean hasNotNullProperty() {
|
public boolean hasNotNullProperty() {
|
||||||
return hasNotNullProperty;
|
return hasNotNullProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isCreateEmptyCompositesEnabled() {
|
||||||
|
return createEmptyCompositesEnabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.component.empty;
|
||||||
|
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public class ComponentEmptyEmbedded {
|
||||||
|
|
||||||
|
private String field1;
|
||||||
|
|
||||||
|
private String field2;
|
||||||
|
|
||||||
|
public String getField1() {
|
||||||
|
return field1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField1(String field1) {
|
||||||
|
this.field1 = field1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getField2() {
|
||||||
|
return field2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setField2(String field2) {
|
||||||
|
this.field2 = field2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.component.empty;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class ComponentEmptyEmbeddedOwner {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private ComponentEmptyEmbedded embedded;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentEmptyEmbedded getEmbedded() {
|
||||||
|
return embedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmbedded(ComponentEmptyEmbedded embedded) {
|
||||||
|
this.embedded = embedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.component.empty;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for empty embedded dirtiness computation.
|
||||||
|
*
|
||||||
|
* @author Laurent Almeras
|
||||||
|
*/
|
||||||
|
public class EmptyCompositesDirtynessTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { ComponentEmptyEmbeddedOwner.class, ComponentEmptyEmbedded.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration configuration) {
|
||||||
|
super.configure( configuration );
|
||||||
|
configuration.getProperties().put( Environment.CREATE_EMPTY_COMPOSITES_ENABLED, Boolean.valueOf( false ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for dirtyness computation consistency when a property is an empty composite.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-7610")
|
||||||
|
public void testCompositesEmpty() {
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
ComponentEmptyEmbeddedOwner owner = new ComponentEmptyEmbeddedOwner();
|
||||||
|
s.persist( owner );
|
||||||
|
|
||||||
|
s.flush();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
|
||||||
|
s.clear();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
owner = (ComponentEmptyEmbeddedOwner) s.get( ComponentEmptyEmbeddedOwner.class, owner.getId() );
|
||||||
|
assertNull( owner.getEmbedded() );
|
||||||
|
owner.setEmbedded( new ComponentEmptyEmbedded() );
|
||||||
|
|
||||||
|
// technically, as all properties are null, update may not be necessary
|
||||||
|
assertFalse( session.isDirty() ); // must be false to avoid unnecessary updates
|
||||||
|
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.component.empty;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for empty embedded dirtiness computation.
|
||||||
|
*
|
||||||
|
* @author Laurent Almeras
|
||||||
|
*/
|
||||||
|
public class EmptyInitializedCompositesDirtynessTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { ComponentEmptyEmbeddedOwner.class, ComponentEmptyEmbedded.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration configuration) {
|
||||||
|
super.configure( configuration );
|
||||||
|
configuration.getProperties().put( Environment.CREATE_EMPTY_COMPOSITES_ENABLED, Boolean.valueOf( true ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for dirtyness computation consistency when a property is an empty composite and that empty composite
|
||||||
|
* initialization is set.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-7610")
|
||||||
|
public void testInitializedCompositesEmpty() {
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
ComponentEmptyEmbeddedOwner owner = new ComponentEmptyEmbeddedOwner();
|
||||||
|
s.persist( owner );
|
||||||
|
|
||||||
|
s.flush();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
|
||||||
|
s.clear();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
owner = (ComponentEmptyEmbeddedOwner) s.get( ComponentEmptyEmbeddedOwner.class, owner.getId() );
|
||||||
|
assertNotNull( owner.getEmbedded() );
|
||||||
|
assertFalse( s.isDirty() );
|
||||||
|
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.component.empty;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for empty embedded dirtiness computation.
|
||||||
|
*
|
||||||
|
* @author Laurent Almeras
|
||||||
|
*/
|
||||||
|
public class EmptyInitializedCompositesTest extends BaseCoreFunctionalTestCase {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
|
return new Class[] { ComponentEmptyEmbeddedOwner.class, ComponentEmptyEmbedded.class };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(Configuration configuration) {
|
||||||
|
super.configure( configuration );
|
||||||
|
configuration.getProperties().put( Environment.CREATE_EMPTY_COMPOSITES_ENABLED, Boolean.valueOf( true ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test empty composite initialization.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@TestForIssue(jiraKey = "HHH-7610")
|
||||||
|
public void testCompositesEmpty() {
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
|
||||||
|
ComponentEmptyEmbeddedOwner owner = new ComponentEmptyEmbeddedOwner();
|
||||||
|
s.persist( owner );
|
||||||
|
|
||||||
|
s.flush();
|
||||||
|
s.getTransaction().commit();
|
||||||
|
|
||||||
|
s.clear();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
owner = (ComponentEmptyEmbeddedOwner) s.get( ComponentEmptyEmbeddedOwner.class, owner.getId() );
|
||||||
|
assertNotNull( owner.getEmbedded() );
|
||||||
|
assertFalse( s.isDirty() );
|
||||||
|
|
||||||
|
owner.setEmbedded( null );
|
||||||
|
assertFalse( s.isDirty() ); // must be false to avoid unnecessary updates
|
||||||
|
|
||||||
|
s.getTransaction().rollback();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue