HHH-12633 Fix dirty tracking when previous state is unfetched

This commit is contained in:
Guillaume Smet 2018-05-25 18:02:26 +02:00
parent 3981c14e9e
commit 85aa8dc019
2 changed files with 112 additions and 4 deletions

View File

@ -286,7 +286,7 @@ public class TypeHelper {
* @param previousState The baseline state of the entity
* @param includeColumns Columns to be included in the dirty checking, per property
* @param session The session from which the dirty check request originated.
*
*
* @return Array containing indices of the dirty properties, or null if no properties considered dirty.
*/
public static int[] findDirty(
@ -300,9 +300,10 @@ public class TypeHelper {
int span = properties.length;
for ( int i = 0; i < span; i++ ) {
final boolean dirty = currentState[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY
&& properties[i].isDirtyCheckable()
&& properties[i].getType().isDirty( previousState[i], currentState[i], includeColumns[i], session );
final boolean dirty = currentState[i] != LazyPropertyInitializer.UNFETCHED_PROPERTY &&
( previousState[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ||
( properties[i].isDirtyCheckable()
&& properties[i].getType().isDirty( previousState[i], currentState[i], includeColumns[i], session ) ) );
if ( dirty ) {
if ( results == null ) {
results = new int[span];

View File

@ -0,0 +1,107 @@
/*
* 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.bytecode.enhancement.lazy;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* @author Guillaume Smet
*/
@TestForIssue(jiraKey = "HHH-12633")
@RunWith(BytecodeEnhancerRunner.class)
@CustomEnhancementContext( {EnhancerTestContext.class, LazyInitializationWithoutInlineDirtyTrackingTest.NoInlineDirtyTrackingContext.class} )
public class LazyInitializationWithoutInlineDirtyTrackingTest extends BaseCoreFunctionalTestCase {
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class<?>[]{ File.class };
}
@Test
public void test() {
doInHibernate( this::sessionFactory, s -> {
File file = new File();
file.setId( 1L );
file.setName( "file" );
file.setBytes( new byte[]{ 0 } );
s.persist( file );
} );
doInHibernate( this::sessionFactory, s -> {
File file = s.find( File.class, 1L );
file.setBytes( new byte[]{ 1 } );
s.persist( file );
} );
}
// --- //
@Entity
@Table(name = "FILE")
public static class File {
@Id
private Long id;
private String name;
@Column(name = "bytes", columnDefinition = "BLOB")
@Lob
@Basic(fetch = FetchType.LAZY)
private byte[] bytes;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public byte[] getBytes() {
return bytes;
}
public void setBytes(byte[] bytes) {
this.bytes = bytes;
}
}
public static class NoInlineDirtyTrackingContext extends EnhancerTestContext {
@Override
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
return false;
}
}
}