HHH-12770 - Document @NotFound(action = NotFoundAction.IGNORE) and FetchType.LAZY behavior
This commit is contained in:
parent
6c5e172609
commit
0ab6c1178b
|
@ -425,6 +425,12 @@ However, you can configure this behavior so that Hibernate can ignore such an Ex
|
|||
|
||||
To ignore non-existing parent entity references, even though not really recommended, it's possible to use the annotation `org.hibernate.annotation.NotFound` annotation with a value of `org.hibernate.annotations.NotFoundAction.IGNORE`.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
`@ManyToOne` and `@OneToOne` associations annotated with `@NotFound(action = NotFoundAction.IGNORE)` are always fetched eagerly
|
||||
even if you set the `fetch` attribute to `FetchType.LAZY`.
|
||||
====
|
||||
|
||||
Considering the following `City` and `Person` entity mappings:
|
||||
|
||||
[[associations-not-found-domain-model-example]]
|
||||
|
@ -439,7 +445,7 @@ include::{sourcedir}/NotFoundTest.java[tags=associations-not-found-domain-model-
|
|||
If we have the following entities in our database:
|
||||
|
||||
[[associations-not-found-persist-example]]
|
||||
.`@NotFound` mapping example
|
||||
.`@NotFound` persist example
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
|
|
|
@ -82,7 +82,7 @@ public class NotFoundTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
private String cityName;
|
||||
|
||||
@ManyToOne( fetch = FetchType.LAZY )
|
||||
@ManyToOne
|
||||
@NotFound ( action = NotFoundAction.IGNORE )
|
||||
@JoinColumn(
|
||||
name = "cityName",
|
||||
|
|
|
@ -1750,6 +1750,7 @@ public final class AnnotationBinder {
|
|||
Cascade hibernateCascade = property.getAnnotation( Cascade.class );
|
||||
NotFound notFound = property.getAnnotation( NotFound.class );
|
||||
boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
|
||||
matchIgnoreNotFoundWithFetchType(propertyHolder.getEntityName(), property.getName(), ignoreNotFound, ann.fetch());
|
||||
OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
|
||||
boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
|
||||
JoinTable assocTable = propertyHolder.getJoinTable( property );
|
||||
|
@ -1794,6 +1795,7 @@ public final class AnnotationBinder {
|
|||
Cascade hibernateCascade = property.getAnnotation( Cascade.class );
|
||||
NotFound notFound = property.getAnnotation( NotFound.class );
|
||||
boolean ignoreNotFound = notFound != null && notFound.action().equals( NotFoundAction.IGNORE );
|
||||
matchIgnoreNotFoundWithFetchType(propertyHolder.getEntityName(), property.getName(), ignoreNotFound, ann.fetch());
|
||||
OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
|
||||
boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals( onDeleteAnn.action() );
|
||||
JoinTable assocTable = propertyHolder.getJoinTable( property );
|
||||
|
@ -3525,4 +3527,14 @@ public final class AnnotationBinder {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void matchIgnoreNotFoundWithFetchType(
|
||||
String entity,
|
||||
String association,
|
||||
boolean ignoreNotFound,
|
||||
FetchType fetchType) {
|
||||
if ( ignoreNotFound && fetchType == FetchType.LAZY ) {
|
||||
LOG.ignoreNotFoundWithFetchTypeLazy( entity, association );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1818,4 +1818,10 @@ public interface CoreMessageLogger extends BasicLogger {
|
|||
@LogMessage(level = INFO)
|
||||
@Message(value = "Using JtaPlatform implementation: [%s]", id = 490)
|
||||
void usingJtaPlatform(String jtaPlatformClassName);
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(value = "The [%2$s] association in the [%1$s] entity uses both @NotFound(action = NotFoundAction.IGNORE) and FetchType.LAZY. " +
|
||||
"The NotFoundAction.IGNORE @ManyToOne and @OneToOne associations are always fetched eagerly.", id = 491)
|
||||
void ignoreNotFoundWithFetchTypeLazy(String entity, String association);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* 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.annotations.formula;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.LazyInitializationException;
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@TestForIssue(jiraKey = "HHH-12770")
|
||||
public class JoinFormulaManyToOneLazyFetchingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Stock.class,
|
||||
StockCode.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
StockCode code = new StockCode();
|
||||
code.setId( 1L );
|
||||
code.setCopeType( CodeType.TYPE_A );
|
||||
code.setRefNumber( "ABC" );
|
||||
entityManager.persist( code );
|
||||
|
||||
Stock stock1 = new Stock();
|
||||
stock1.setId( 1L );
|
||||
stock1.setCode( code );
|
||||
entityManager.persist( stock1 );
|
||||
|
||||
Stock stock2 = new Stock();
|
||||
stock2.setId( 2L );
|
||||
entityManager.persist( stock2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyLoading() {
|
||||
List<Stock> stocks = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"SELECT s FROM Stock s", Stock.class )
|
||||
.getResultList();
|
||||
} );
|
||||
assertEquals( 2, stocks.size() );
|
||||
|
||||
try {
|
||||
assertEquals( "ABC", stocks.get( 0 ).getCode().getRefNumber() );
|
||||
|
||||
fail( "Should have thrown LazyInitializationException" );
|
||||
}
|
||||
catch (LazyInitializationException expected) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEagerLoading() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
List<Stock> stocks = entityManager.createQuery(
|
||||
"SELECT s FROM Stock s", Stock.class )
|
||||
.getResultList();
|
||||
|
||||
assertEquals( 2, stocks.size() );
|
||||
assertEquals( "ABC", stocks.get( 0 ).getCode().getRefNumber() );
|
||||
|
||||
try {
|
||||
stocks.get( 1 ).getCode().getRefNumber();
|
||||
|
||||
fail( "Should have thrown EntityNotFoundException" );
|
||||
}
|
||||
catch (EntityNotFoundException expected) {
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Stock")
|
||||
public static class Stock implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumnOrFormula(column = @JoinColumn(name = "CODE_ID", referencedColumnName = "ID"))
|
||||
@JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "TYPE", value = "'TYPE_A'"))
|
||||
private StockCode code;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public StockCode getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(StockCode code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "StockCode")
|
||||
public static class StockCode implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@Id
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "TYPE")
|
||||
private CodeType copeType;
|
||||
|
||||
private String refNumber;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CodeType getCopeType() {
|
||||
return copeType;
|
||||
}
|
||||
|
||||
public void setCopeType(CodeType copeType) {
|
||||
this.copeType = copeType;
|
||||
}
|
||||
|
||||
public String getRefNumber() {
|
||||
return refNumber;
|
||||
}
|
||||
|
||||
public void setRefNumber(String refNumber) {
|
||||
this.refNumber = refNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CodeType {
|
||||
TYPE_A, TYPE_B;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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.annotations.formula;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.LazyInitializationException;
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.boot.model.process.internal.ScanningCoordinator;
|
||||
import org.hibernate.cfg.AnnotationBinder;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.logger.LoggerInspectionRule;
|
||||
import org.hibernate.testing.logger.Triggerable;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@TestForIssue(jiraKey = "HHH-12770")
|
||||
public class JoinFormulaManyToOneNotIgnoreLazyFetchingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Rule
|
||||
public LoggerInspectionRule logInspection = new LoggerInspectionRule(
|
||||
Logger.getMessageLogger( CoreMessageLogger.class, AnnotationBinder.class.getName() )
|
||||
);
|
||||
|
||||
private Triggerable triggerable = logInspection.watchForLogMessages( "HHH000491" );
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Stock.class,
|
||||
StockCode.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
StockCode code = new StockCode();
|
||||
code.setId( 1L );
|
||||
code.setCopeType( CodeType.TYPE_A );
|
||||
code.setRefNumber( "ABC" );
|
||||
entityManager.persist( code );
|
||||
|
||||
Stock stock1 = new Stock();
|
||||
stock1.setId( 1L );
|
||||
stock1.setCode( code );
|
||||
entityManager.persist( stock1 );
|
||||
|
||||
Stock stock2 = new Stock();
|
||||
stock2.setId( 2L );
|
||||
entityManager.persist( stock2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyLoading() {
|
||||
|
||||
assertEquals( "HHH000491: The [code] association in the [org.hibernate.test.annotations.formula.JoinFormulaManyToOneNotIgnoreLazyFetchingTest$Stock] entity uses both @NotFound(action = NotFoundAction.IGNORE) and FetchType.LAZY. The NotFoundAction.IGNORE @ManyToOne and @OneToOne associations are always fetched eagerly.", triggerable.triggerMessage() );
|
||||
|
||||
List<Stock> stocks = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"SELECT s FROM Stock s", Stock.class )
|
||||
.getResultList();
|
||||
} );
|
||||
assertEquals( 2, stocks.size() );
|
||||
|
||||
assertEquals( "ABC", stocks.get( 0 ).getCode().getRefNumber() );
|
||||
assertNull( stocks.get( 1 ).getCode() );
|
||||
}
|
||||
|
||||
@Entity(name = "Stock")
|
||||
public static class Stock implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
@JoinColumnOrFormula(column = @JoinColumn(name = "CODE_ID", referencedColumnName = "ID"))
|
||||
@JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "TYPE", value = "'TYPE_A'"))
|
||||
private StockCode code;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public StockCode getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(StockCode code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "StockCode")
|
||||
public static class StockCode implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@Id
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "TYPE")
|
||||
private CodeType copeType;
|
||||
|
||||
private String refNumber;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CodeType getCopeType() {
|
||||
return copeType;
|
||||
}
|
||||
|
||||
public void setCopeType(CodeType copeType) {
|
||||
this.copeType = copeType;
|
||||
}
|
||||
|
||||
public String getRefNumber() {
|
||||
return refNumber;
|
||||
}
|
||||
|
||||
public void setRefNumber(String refNumber) {
|
||||
this.refNumber = refNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CodeType {
|
||||
TYPE_A, TYPE_B;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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.annotations.formula;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.LazyInitializationException;
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.cfg.AnnotationBinder;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.logger.LoggerInspectionRule;
|
||||
import org.hibernate.testing.logger.Triggerable;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@TestForIssue(jiraKey = "HHH-12770")
|
||||
public class JoinFormulaOneToManyNotIgnoreLazyFetchingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Rule
|
||||
public LoggerInspectionRule logInspection = new LoggerInspectionRule(
|
||||
Logger.getMessageLogger( CoreMessageLogger.class, AnnotationBinder.class.getName() )
|
||||
);
|
||||
|
||||
private Triggerable triggerable = logInspection.watchForLogMessages( "HHH000491" );
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Stock.class,
|
||||
StockCode.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
StockCode code = new StockCode();
|
||||
code.setId( 1L );
|
||||
code.setCopeType( CodeType.TYPE_A );
|
||||
code.setRefNumber( "ABC" );
|
||||
entityManager.persist( code );
|
||||
|
||||
Stock stock1 = new Stock();
|
||||
stock1.setId( 1L );
|
||||
stock1.getCodes().add( code );
|
||||
entityManager.persist( stock1 );
|
||||
|
||||
Stock stock2 = new Stock();
|
||||
stock2.setId( 2L );
|
||||
entityManager.persist( stock2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyLoading() {
|
||||
|
||||
assertFalse( triggerable.wasTriggered() );
|
||||
|
||||
List<Stock> stocks = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"SELECT s FROM Stock s", Stock.class )
|
||||
.getResultList();
|
||||
} );
|
||||
assertEquals( 2, stocks.size() );
|
||||
|
||||
try {
|
||||
assertEquals( "ABC", stocks.get( 0 ).getCodes().get( 0 ).getRefNumber() );
|
||||
|
||||
fail( "Should have thrown LazyInitializationException" );
|
||||
}
|
||||
catch (LazyInitializationException expected) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Stock")
|
||||
public static class Stock implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@OneToMany
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
@JoinColumn(name = "CODE_ID", referencedColumnName = "ID")
|
||||
private List<StockCode> codes = new ArrayList<>( );
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public List<StockCode> getCodes() {
|
||||
return codes;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "StockCode")
|
||||
public static class StockCode implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@Id
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "TYPE")
|
||||
private CodeType copeType;
|
||||
|
||||
private String refNumber;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CodeType getCopeType() {
|
||||
return copeType;
|
||||
}
|
||||
|
||||
public void setCopeType(CodeType copeType) {
|
||||
this.copeType = copeType;
|
||||
}
|
||||
|
||||
public String getRefNumber() {
|
||||
return refNumber;
|
||||
}
|
||||
|
||||
public void setRefNumber(String refNumber) {
|
||||
this.refNumber = refNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CodeType {
|
||||
TYPE_A, TYPE_B;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* 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.annotations.formula;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
import org.hibernate.annotations.JoinColumnOrFormula;
|
||||
import org.hibernate.annotations.JoinFormula;
|
||||
import org.hibernate.annotations.NotFound;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.cfg.AnnotationBinder;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.logger.LoggerInspectionRule;
|
||||
import org.hibernate.testing.logger.Triggerable;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@TestForIssue(jiraKey = "HHH-12770")
|
||||
public class JoinFormulaOneToOneNotIgnoreLazyFetchingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Rule
|
||||
public LoggerInspectionRule logInspection = new LoggerInspectionRule(
|
||||
Logger.getMessageLogger( CoreMessageLogger.class, AnnotationBinder.class.getName() )
|
||||
);
|
||||
|
||||
private Triggerable triggerable = logInspection.watchForLogMessages( "HHH000491" );
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Stock.class,
|
||||
StockCode.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
StockCode code = new StockCode();
|
||||
code.setId( 1L );
|
||||
code.setCopeType( CodeType.TYPE_A );
|
||||
code.setRefNumber( "ABC" );
|
||||
entityManager.persist( code );
|
||||
|
||||
Stock stock1 = new Stock();
|
||||
stock1.setId( 1L );
|
||||
stock1.setCode( code );
|
||||
entityManager.persist( stock1 );
|
||||
|
||||
Stock stock2 = new Stock();
|
||||
stock2.setId( 2L );
|
||||
entityManager.persist( stock2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLazyLoading() {
|
||||
|
||||
assertEquals( "HHH000491: The [code] association in the [org.hibernate.test.annotations.formula.JoinFormulaOneToOneNotIgnoreLazyFetchingTest$Stock] entity uses both @NotFound(action = NotFoundAction.IGNORE) and FetchType.LAZY. The NotFoundAction.IGNORE @ManyToOne and @OneToOne associations are always fetched eagerly.", triggerable.triggerMessage() );
|
||||
|
||||
List<Stock> stocks = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"SELECT s FROM Stock s", Stock.class )
|
||||
.getResultList();
|
||||
} );
|
||||
assertEquals( 2, stocks.size() );
|
||||
|
||||
assertEquals( "ABC", stocks.get( 0 ).getCode().getRefNumber() );
|
||||
assertNull( stocks.get( 1 ).getCode() );
|
||||
}
|
||||
|
||||
@Entity(name = "Stock")
|
||||
public static class Stock implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@NotFound(action = NotFoundAction.IGNORE)
|
||||
@JoinColumnOrFormula(column = @JoinColumn(name = "CODE_ID", referencedColumnName = "ID"))
|
||||
@JoinColumnOrFormula(formula = @JoinFormula(referencedColumnName = "TYPE", value = "'TYPE_A'"))
|
||||
private StockCode code;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public StockCode getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(StockCode code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "StockCode")
|
||||
public static class StockCode implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
private Long id;
|
||||
|
||||
@Id
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "TYPE")
|
||||
private CodeType copeType;
|
||||
|
||||
private String refNumber;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CodeType getCopeType() {
|
||||
return copeType;
|
||||
}
|
||||
|
||||
public void setCopeType(CodeType copeType) {
|
||||
this.copeType = copeType;
|
||||
}
|
||||
|
||||
public String getRefNumber() {
|
||||
return refNumber;
|
||||
}
|
||||
|
||||
public void setRefNumber(String refNumber) {
|
||||
this.refNumber = refNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public enum CodeType {
|
||||
TYPE_A, TYPE_B;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue