HHH-15982 Add parentAccess logic to unique key initializer
This commit is contained in:
parent
39f2482ebf
commit
5f08ffed83
|
@ -378,7 +378,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolveInstance(RowProcessingState rowProcessingState) {
|
public void resolveInstance(RowProcessingState rowProcessingState) {
|
||||||
if ( !missing ) {
|
if ( !missing && !isInitialized ) {
|
||||||
// Special case map proxy to avoid stack overflows
|
// Special case map proxy to avoid stack overflows
|
||||||
// We know that a map proxy will always be of "the right type" so just use that object
|
// We know that a map proxy will always be of "the right type" so just use that object
|
||||||
final LoadingEntityEntry existingLoadingEntry =
|
final LoadingEntityEntry existingLoadingEntry =
|
||||||
|
@ -389,6 +389,9 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
if ( entityInstance == null ) {
|
if ( entityInstance == null ) {
|
||||||
resolveEntityInstance( rowProcessingState, existingLoadingEntry, entityKey.getIdentifier() );
|
resolveEntityInstance( rowProcessingState, existingLoadingEntry, entityKey.getIdentifier() );
|
||||||
}
|
}
|
||||||
|
else if ( existingLoadingEntry != null && existingLoadingEntry.getEntityInitializer() != this ) {
|
||||||
|
isInitialized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.persister.entity.UniqueKeyLoadable;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
|
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
|
|
||||||
|
@ -41,6 +42,15 @@ public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchIn
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final EntityInitializer parentEntityInitializer = getParentEntityInitializer( parentAccess );
|
||||||
|
if ( parentEntityInitializer != null && parentEntityInitializer.getEntityKey() != null ) {
|
||||||
|
// make sure parentEntityInitializer.resolveInstance has been called before
|
||||||
|
parentEntityInitializer.resolveInstance( rowProcessingState );
|
||||||
|
if ( parentEntityInitializer.isInitialized() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( !isAttributeAssignableToConcreteDescriptor() ) {
|
if ( !isAttributeAssignableToConcreteDescriptor() ) {
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
return;
|
return;
|
||||||
|
@ -95,4 +105,10 @@ public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchIn
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EntityInitializer getParentEntityInitializer(FetchParentAccess parentAccess) {
|
||||||
|
if ( parentAccess != null ) {
|
||||||
|
return parentAccess.findFirstEntityInitializer();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ import static org.hibernate.internal.log.LoggingHelper.toLoggableString;
|
||||||
public class EntitySelectFetchInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
public class EntitySelectFetchInitializer extends AbstractFetchParentAccess implements EntityInitializer {
|
||||||
private static final String CONCRETE_NAME = EntitySelectFetchInitializer.class.getSimpleName();
|
private static final String CONCRETE_NAME = EntitySelectFetchInitializer.class.getSimpleName();
|
||||||
|
|
||||||
private final FetchParentAccess parentAccess;
|
protected final FetchParentAccess parentAccess;
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
private final boolean isEnhancedForLazyLoading;
|
private final boolean isEnhancedForLazyLoading;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.mapping.converted.converter.onetoone;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.hibernate.engine.internal.StatisticalLoggingSessionEventListener;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.AttributeConverter;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Convert;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Marco Belladelli
|
||||||
|
*/
|
||||||
|
@SessionFactory
|
||||||
|
@DomainModel(annotatedClasses = {
|
||||||
|
BidirectionalOneToOneWithConverterEagerTest.FooEntity.class,
|
||||||
|
BidirectionalOneToOneWithConverterEagerTest.BarEntity.class,
|
||||||
|
})
|
||||||
|
@JiraKey("HHH-15950")
|
||||||
|
public class BidirectionalOneToOneWithConverterEagerTest {
|
||||||
|
@BeforeAll
|
||||||
|
public void setUp(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
BarEntity bar = new BarEntity();
|
||||||
|
bar.setBusinessId( new BusinessId( UUID.randomUUID().toString() ) );
|
||||||
|
bar.setaDouble( 0.5 );
|
||||||
|
|
||||||
|
FooEntity foo = new FooEntity();
|
||||||
|
foo.setBusinessId( new BusinessId( UUID.randomUUID().toString() ) );
|
||||||
|
foo.setName( "foo_name" );
|
||||||
|
|
||||||
|
foo.setBar( bar );
|
||||||
|
bar.setFoo( foo );
|
||||||
|
|
||||||
|
session.persist( bar );
|
||||||
|
session.persist( foo );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
session.createMutationQuery( "delete from FooEntity" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete from BarEntity" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBidirectionalFetch(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
FooEntity foo = session.find( FooEntity.class, 1L );
|
||||||
|
|
||||||
|
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
||||||
|
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
||||||
|
@Override
|
||||||
|
public void jdbcExecuteStatementStart() {
|
||||||
|
super.jdbcExecuteStatementStart();
|
||||||
|
queryExecutionCount.getAndIncrement();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
BarEntity bar = foo.getBar();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( 0.5, bar.getaDouble() );
|
||||||
|
|
||||||
|
FooEntity associatedFoo = bar.getFoo();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( "foo_name", associatedFoo.getName() );
|
||||||
|
assertEquals( foo, associatedFoo );
|
||||||
|
|
||||||
|
assertEquals( bar, associatedFoo.getBar() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBidirectionalFetchInverse(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
BarEntity bar = session.find( BarEntity.class, 1L );
|
||||||
|
|
||||||
|
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
||||||
|
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
||||||
|
@Override
|
||||||
|
public void jdbcExecuteStatementStart() {
|
||||||
|
super.jdbcExecuteStatementStart();
|
||||||
|
queryExecutionCount.getAndIncrement();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
FooEntity foo = bar.getFoo();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( "foo_name", foo.getName() );
|
||||||
|
|
||||||
|
BarEntity associatedBar = foo.getBar();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( 0.5, associatedBar.getaDouble() );
|
||||||
|
assertEquals( bar, associatedBar );
|
||||||
|
|
||||||
|
assertEquals( foo, associatedBar.getFoo() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BusinessId implements Serializable {
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public BusinessId() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessId(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BusinessIdConverter implements AttributeConverter<BusinessId, String> {
|
||||||
|
@Override
|
||||||
|
public String convertToDatabaseColumn(BusinessId uuid) {
|
||||||
|
return uuid != null ? uuid.getValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BusinessId convertToEntityAttribute(String s) {
|
||||||
|
return s == null ? null : new BusinessId( s );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "FooEntity")
|
||||||
|
@Table(name = "foo")
|
||||||
|
public static class FooEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "uuid", unique = true, updatable = false)
|
||||||
|
@Convert(converter = BusinessIdConverter.class)
|
||||||
|
private BusinessId businessId;
|
||||||
|
|
||||||
|
@OneToOne(fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "bar_uuid", referencedColumnName = "uuid", nullable = false, updatable = false)
|
||||||
|
private BarEntity bar;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public BarEntity getBar() {
|
||||||
|
return bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBar(BarEntity bar) {
|
||||||
|
this.bar = bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessId getBusinessId() {
|
||||||
|
return businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBusinessId(BusinessId businessId) {
|
||||||
|
this.businessId = businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "BarEntity")
|
||||||
|
@Table(name = "bar")
|
||||||
|
public static class BarEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "uuid", unique = true, updatable = false)
|
||||||
|
@Convert(converter = BusinessIdConverter.class)
|
||||||
|
private BusinessId businessId;
|
||||||
|
|
||||||
|
@OneToOne(fetch = FetchType.EAGER, mappedBy = "bar")
|
||||||
|
private FooEntity foo;
|
||||||
|
|
||||||
|
private Double aDouble;
|
||||||
|
|
||||||
|
public FooEntity getFoo() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFoo(FooEntity foo) {
|
||||||
|
this.foo = foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BusinessId getBusinessId() {
|
||||||
|
return businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBusinessId(BusinessId businessId) {
|
||||||
|
this.businessId = businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getaDouble() {
|
||||||
|
return aDouble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setaDouble(Double aDouble) {
|
||||||
|
this.aDouble = aDouble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,10 +4,9 @@
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
* 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
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.mapping.converted.converter;
|
package org.hibernate.orm.test.mapping.converted.converter.onetoone;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
@ -17,6 +16,8 @@ import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.AttributeConverter;
|
import jakarta.persistence.AttributeConverter;
|
||||||
|
@ -37,24 +38,21 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@DomainModel(annotatedClasses = {
|
@DomainModel(annotatedClasses = {
|
||||||
BidirectionalOneToOneWithConverterTest.FooEntity.class,
|
BidirectionalOneToOneWithConverterLazyTest.FooEntity.class,
|
||||||
BidirectionalOneToOneWithConverterTest.BarEntity.class,
|
BidirectionalOneToOneWithConverterLazyTest.BarEntity.class,
|
||||||
})
|
})
|
||||||
@JiraKey("HHH-15950")
|
@JiraKey("HHH-15950")
|
||||||
public class BidirectionalOneToOneWithConverterTest {
|
public class BidirectionalOneToOneWithConverterLazyTest {
|
||||||
@Test
|
@BeforeAll
|
||||||
public void testBidirectionalFetch(SessionFactoryScope scope) {
|
public void setUp(SessionFactoryScope scope) {
|
||||||
String name = "foo_name";
|
|
||||||
Date date = new Date();
|
|
||||||
|
|
||||||
scope.inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
BarEntity bar = new BarEntity();
|
BarEntity bar = new BarEntity();
|
||||||
bar.setBusinessId( new BusinessId( UUID.randomUUID().toString() ) );
|
bar.setBusinessId( new BusinessId( UUID.randomUUID().toString() ) );
|
||||||
bar.setDate( date );
|
bar.setaDouble( 0.5 );
|
||||||
|
|
||||||
FooEntity foo = new FooEntity();
|
FooEntity foo = new FooEntity();
|
||||||
foo.setBusinessId( new BusinessId( UUID.randomUUID().toString() ) );
|
foo.setBusinessId( new BusinessId( UUID.randomUUID().toString() ) );
|
||||||
foo.setName( name );
|
foo.setName( "foo_name" );
|
||||||
|
|
||||||
foo.setBar( bar );
|
foo.setBar( bar );
|
||||||
bar.setFoo( foo );
|
bar.setFoo( foo );
|
||||||
|
@ -62,10 +60,20 @@ public class BidirectionalOneToOneWithConverterTest {
|
||||||
session.persist( bar );
|
session.persist( bar );
|
||||||
session.persist( foo );
|
session.persist( foo );
|
||||||
} );
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
session.createMutationQuery( "delete from FooEntity" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete from BarEntity" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBidirectionalFetch(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
FooEntity foo = session.find( FooEntity.class, 1L );
|
FooEntity foo = session.find( FooEntity.class, 1L );
|
||||||
assertEquals( name, foo.getName() );
|
|
||||||
|
|
||||||
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
||||||
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
||||||
|
@ -77,24 +85,44 @@ public class BidirectionalOneToOneWithConverterTest {
|
||||||
} );
|
} );
|
||||||
|
|
||||||
BarEntity bar = foo.getBar();
|
BarEntity bar = foo.getBar();
|
||||||
// no queries should be executed
|
|
||||||
assertEquals( 0, queryExecutionCount.get() );
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
assertEquals( date, bar.getDate() );
|
assertEquals( 0.5, bar.getaDouble() );
|
||||||
|
|
||||||
FooEntity associatedFoo = bar.getFoo();
|
FooEntity associatedFoo = bar.getFoo();
|
||||||
// no queries should be executed
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
assertEquals(0, queryExecutionCount.get());
|
assertEquals( "foo_name", associatedFoo.getName() );
|
||||||
assertEquals( foo, associatedFoo );
|
assertEquals( foo, associatedFoo );
|
||||||
|
|
||||||
|
assertEquals( bar, associatedFoo.getBar() );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo marco : verifica che get su associazione non faccia altra query
|
@Test
|
||||||
// foo.getBar() - non deve fare query
|
public void testBidirectionalFetchInverse(SessionFactoryScope scope) {
|
||||||
// bar.getFoo() - non deve fare query + deve essere stessa instance di quello col find
|
scope.inTransaction( session -> {
|
||||||
// todo marco : provare anche contrario (session.find(Bar.class, 1L);
|
BarEntity bar = session.find( BarEntity.class, 1L );
|
||||||
|
|
||||||
// todo marco : fare un altro test con associazione EAGER
|
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
||||||
// questo dovrebbe fare il detect della circularity
|
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
||||||
|
@Override
|
||||||
|
public void jdbcExecuteStatementStart() {
|
||||||
|
super.jdbcExecuteStatementStart();
|
||||||
|
queryExecutionCount.getAndIncrement();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
FooEntity foo = bar.getFoo();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( "foo_name", foo.getName() );
|
||||||
|
|
||||||
|
BarEntity associatedBar = foo.getBar();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( 0.5, associatedBar.getaDouble() );
|
||||||
|
assertEquals( bar, associatedBar );
|
||||||
|
|
||||||
|
assertEquals( foo, associatedBar.getFoo() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
public static class BusinessId implements Serializable {
|
public static class BusinessId implements Serializable {
|
||||||
private String value;
|
private String value;
|
||||||
|
@ -127,7 +155,7 @@ public class BidirectionalOneToOneWithConverterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "FooEntity")
|
||||||
@Table(name = "foo")
|
@Table(name = "foo")
|
||||||
public static class FooEntity {
|
public static class FooEntity {
|
||||||
@Id
|
@Id
|
||||||
|
@ -177,7 +205,7 @@ public class BidirectionalOneToOneWithConverterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity(name = "BarEntity")
|
||||||
@Table(name = "bar")
|
@Table(name = "bar")
|
||||||
public static class BarEntity {
|
public static class BarEntity {
|
||||||
@Id
|
@Id
|
||||||
|
@ -191,7 +219,7 @@ public class BidirectionalOneToOneWithConverterTest {
|
||||||
@OneToOne(fetch = FetchType.LAZY, mappedBy = "bar")
|
@OneToOne(fetch = FetchType.LAZY, mappedBy = "bar")
|
||||||
private FooEntity foo;
|
private FooEntity foo;
|
||||||
|
|
||||||
private Date date;
|
private Double aDouble;
|
||||||
|
|
||||||
public FooEntity getFoo() {
|
public FooEntity getFoo() {
|
||||||
return foo;
|
return foo;
|
||||||
|
@ -217,12 +245,12 @@ public class BidirectionalOneToOneWithConverterTest {
|
||||||
this.businessId = businessId;
|
this.businessId = businessId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getDate() {
|
public Double getaDouble() {
|
||||||
return date;
|
return aDouble;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDate(Date date) {
|
public void setaDouble(Double aDouble) {
|
||||||
this.date = date;
|
this.aDouble = aDouble;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.onetoone.bidirectional;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import org.hibernate.engine.internal.StatisticalLoggingSessionEventListener;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Marco Belladelli
|
||||||
|
*/
|
||||||
|
@SessionFactory
|
||||||
|
@DomainModel(annotatedClasses = {
|
||||||
|
BidirectionalOneToOneEagerFKTest.FooEntity.class,
|
||||||
|
BidirectionalOneToOneEagerFKTest.BarEntity.class
|
||||||
|
})
|
||||||
|
public class BidirectionalOneToOneEagerFKTest {
|
||||||
|
@BeforeAll
|
||||||
|
public void setUp(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
BarEntity bar = new BarEntity();
|
||||||
|
bar.setBusinessId( 1L );
|
||||||
|
bar.setaDouble( 0.5 );
|
||||||
|
|
||||||
|
FooEntity foo = new FooEntity();
|
||||||
|
foo.setBusinessId( 2L );
|
||||||
|
foo.setName( "foo_name" );
|
||||||
|
|
||||||
|
foo.setBar( bar );
|
||||||
|
bar.setFoo( foo );
|
||||||
|
|
||||||
|
session.persist( bar );
|
||||||
|
session.persist( foo );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
session.createMutationQuery( "delete from FooEntity" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete from BarEntity" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBidirectionalFetchJoinColumnSide(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
||||||
|
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
||||||
|
@Override
|
||||||
|
public void jdbcExecuteStatementStart() {
|
||||||
|
super.jdbcExecuteStatementStart();
|
||||||
|
queryExecutionCount.getAndIncrement();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
FooEntity foo = session.find( FooEntity.class, 1L );
|
||||||
|
|
||||||
|
BarEntity bar = foo.getBar();
|
||||||
|
assertEquals( 1, queryExecutionCount.get() );
|
||||||
|
assertEquals( 0.5, bar.getaDouble() );
|
||||||
|
|
||||||
|
FooEntity associatedFoo = bar.getFoo();
|
||||||
|
assertEquals( 1, queryExecutionCount.get() );
|
||||||
|
assertEquals( "foo_name", associatedFoo.getName() );
|
||||||
|
assertEquals( foo, associatedFoo );
|
||||||
|
|
||||||
|
assertEquals( bar, associatedFoo.getBar() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBidirectionalFetchMappedBySide(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
||||||
|
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
||||||
|
@Override
|
||||||
|
public void jdbcExecuteStatementStart() {
|
||||||
|
super.jdbcExecuteStatementStart();
|
||||||
|
queryExecutionCount.getAndIncrement();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
BarEntity bar = session.find( BarEntity.class, 1L );
|
||||||
|
assertEquals( 1, queryExecutionCount.get() );
|
||||||
|
|
||||||
|
FooEntity foo = bar.getFoo();
|
||||||
|
assertEquals( 1, queryExecutionCount.get() );
|
||||||
|
assertEquals( "foo_name", foo.getName() );
|
||||||
|
|
||||||
|
BarEntity associatedBar = foo.getBar();
|
||||||
|
assertEquals( 1, queryExecutionCount.get() );
|
||||||
|
assertEquals( 0.5, associatedBar.getaDouble() );
|
||||||
|
assertEquals( bar, associatedBar );
|
||||||
|
|
||||||
|
assertEquals( foo, associatedBar.getFoo() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "FooEntity")
|
||||||
|
@Table(name = "foo")
|
||||||
|
public static class FooEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "business_id", unique = true, updatable = false)
|
||||||
|
private Long businessId;
|
||||||
|
|
||||||
|
@OneToOne(fetch = FetchType.EAGER)
|
||||||
|
@JoinColumn(name = "bar_business_id", referencedColumnName = "business_id", nullable = false, updatable = false)
|
||||||
|
private BarEntity bar;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public BarEntity getBar() {
|
||||||
|
return bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBar(BarEntity bar) {
|
||||||
|
this.bar = bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBusinessId() {
|
||||||
|
return businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBusinessId(Long businessId) {
|
||||||
|
this.businessId = businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "BarEntity")
|
||||||
|
@Table(name = "bar")
|
||||||
|
public static class BarEntity {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "business_id", unique = true, updatable = false)
|
||||||
|
private Long businessId;
|
||||||
|
|
||||||
|
@OneToOne(fetch = FetchType.EAGER, mappedBy = "bar")
|
||||||
|
private FooEntity foo;
|
||||||
|
|
||||||
|
private Double aDouble;
|
||||||
|
|
||||||
|
public FooEntity getFoo() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFoo(FooEntity foo) {
|
||||||
|
this.foo = foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBusinessId() {
|
||||||
|
return businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBusinessId(Long businessId) {
|
||||||
|
this.businessId = businessId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getaDouble() {
|
||||||
|
return aDouble;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setaDouble(Double aDouble) {
|
||||||
|
this.aDouble = aDouble;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,3 @@
|
||||||
/*
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
|
@ -13,7 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.onetoone.bidirectional;
|
package org.hibernate.orm.test.onetoone.bidirectional;
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.hibernate.engine.internal.StatisticalLoggingSessionEventListener;
|
import org.hibernate.engine.internal.StatisticalLoggingSessionEventListener;
|
||||||
|
@ -21,6 +13,8 @@ import org.hibernate.engine.internal.StatisticalLoggingSessionEventListener;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
|
@ -39,24 +33,20 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
*/
|
*/
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@DomainModel(annotatedClasses = {
|
@DomainModel(annotatedClasses = {
|
||||||
BidirectionalOneToOneInstanceTest.FooEntity.class,
|
BidirectionalOneToOneLazyFKTest.FooEntity.class,
|
||||||
BidirectionalOneToOneInstanceTest.BarEntity.class
|
BidirectionalOneToOneLazyFKTest.BarEntity.class
|
||||||
})
|
})
|
||||||
public class BidirectionalOneToOneInstanceTest {
|
public class BidirectionalOneToOneLazyFKTest {
|
||||||
|
@BeforeAll
|
||||||
@Test
|
public void setUp(SessionFactoryScope scope) {
|
||||||
public void testBidirectionalFetch(SessionFactoryScope scope) {
|
|
||||||
String name = "foo_name";
|
|
||||||
Date date = new Date();
|
|
||||||
|
|
||||||
scope.inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
BarEntity bar = new BarEntity();
|
BarEntity bar = new BarEntity();
|
||||||
bar.setBusinessId( 1L );
|
bar.setBusinessId( 1L );
|
||||||
bar.setDate( date );
|
bar.setaDouble( 0.5 );
|
||||||
|
|
||||||
FooEntity foo = new FooEntity();
|
FooEntity foo = new FooEntity();
|
||||||
foo.setBusinessId( 2L );
|
foo.setBusinessId( 2L );
|
||||||
foo.setName( name );
|
foo.setName( "foo_name" );
|
||||||
|
|
||||||
foo.setBar( bar );
|
foo.setBar( bar );
|
||||||
bar.setFoo( foo );
|
bar.setFoo( foo );
|
||||||
|
@ -64,7 +54,18 @@ public class BidirectionalOneToOneInstanceTest {
|
||||||
session.persist( bar );
|
session.persist( bar );
|
||||||
session.persist( foo );
|
session.persist( foo );
|
||||||
} );
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
session.createMutationQuery( "delete from FooEntity" ).executeUpdate();
|
||||||
|
session.createMutationQuery( "delete from BarEntity" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBidirectionalFetchJoinColumnSide(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
FooEntity foo = session.find( FooEntity.class, 1L );
|
FooEntity foo = session.find( FooEntity.class, 1L );
|
||||||
|
|
||||||
|
@ -77,17 +78,43 @@ public class BidirectionalOneToOneInstanceTest {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
assertEquals( name, foo.getName() );
|
|
||||||
|
|
||||||
BarEntity bar = foo.getBar();
|
BarEntity bar = foo.getBar();
|
||||||
// no queries should be executed
|
|
||||||
assertEquals( 0, queryExecutionCount.get() );
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
assertEquals( date, bar.getDate() );
|
assertEquals( 0.5, bar.getaDouble() );
|
||||||
|
|
||||||
FooEntity associatedFoo = bar.getFoo();
|
FooEntity associatedFoo = bar.getFoo();
|
||||||
// no queries should be executed
|
|
||||||
assertEquals( 0, queryExecutionCount.get() );
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( "foo_name", associatedFoo.getName() );
|
||||||
assertEquals( foo, associatedFoo );
|
assertEquals( foo, associatedFoo );
|
||||||
|
|
||||||
|
assertEquals( bar, associatedFoo.getBar() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBidirectionalFetchMappedBySide(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
BarEntity bar = session.find( BarEntity.class, 1L );
|
||||||
|
|
||||||
|
final AtomicInteger queryExecutionCount = new AtomicInteger();
|
||||||
|
session.getEventListenerManager().addListener( new StatisticalLoggingSessionEventListener() {
|
||||||
|
@Override
|
||||||
|
public void jdbcExecuteStatementStart() {
|
||||||
|
super.jdbcExecuteStatementStart();
|
||||||
|
queryExecutionCount.getAndIncrement();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
FooEntity foo = bar.getFoo();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( "foo_name", foo.getName() );
|
||||||
|
|
||||||
|
BarEntity associatedBar = foo.getBar();
|
||||||
|
assertEquals( 0, queryExecutionCount.get() );
|
||||||
|
assertEquals( 0.5, associatedBar.getaDouble() );
|
||||||
|
assertEquals( bar, associatedBar );
|
||||||
|
|
||||||
|
assertEquals( foo, associatedBar.getFoo() );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,11 +125,11 @@ public class BidirectionalOneToOneInstanceTest {
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Column(name = "uuid", unique = true, updatable = false)
|
@Column(name = "business_id", unique = true, updatable = false)
|
||||||
private Long businessId;
|
private Long businessId;
|
||||||
|
|
||||||
@OneToOne(fetch = FetchType.LAZY)
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "bar_uuid", referencedColumnName = "uuid", nullable = false, updatable = false)
|
@JoinColumn(name = "bar_business_id", referencedColumnName = "business_id", nullable = false, updatable = false)
|
||||||
private BarEntity bar;
|
private BarEntity bar;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -147,13 +174,13 @@ public class BidirectionalOneToOneInstanceTest {
|
||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@Column(name = "uuid", unique = true, updatable = false)
|
@Column(name = "business_id", unique = true, updatable = false)
|
||||||
private Long businessId;
|
private Long businessId;
|
||||||
|
|
||||||
@OneToOne(fetch = FetchType.LAZY, mappedBy = "bar")
|
@OneToOne(fetch = FetchType.LAZY, mappedBy = "bar")
|
||||||
private FooEntity foo;
|
private FooEntity foo;
|
||||||
|
|
||||||
private Date date;
|
private Double aDouble;
|
||||||
|
|
||||||
public FooEntity getFoo() {
|
public FooEntity getFoo() {
|
||||||
return foo;
|
return foo;
|
||||||
|
@ -179,12 +206,12 @@ public class BidirectionalOneToOneInstanceTest {
|
||||||
this.businessId = businessId;
|
this.businessId = businessId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getDate() {
|
public Double getaDouble() {
|
||||||
return date;
|
return aDouble;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDate(Date date) {
|
public void setaDouble(Double aDouble) {
|
||||||
this.date = date;
|
this.aDouble = aDouble;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue