Merge remote-tracking branch 'upstream/main' into wip/6.0

This commit is contained in:
Andrea Boriero 2021-09-07 17:22:42 +02:00
commit 236e901cd1
11 changed files with 429 additions and 200 deletions

View File

@ -142,7 +142,7 @@ ext {
mariadb: 'org.mariadb.jdbc:mariadb-java-client:2.2.3', mariadb: 'org.mariadb.jdbc:mariadb-java-client:2.2.3',
cockroachdb: 'org.postgresql:postgresql:42.2.8', cockroachdb: 'org.postgresql:postgresql:42.2.8',
oracle: 'com.oracle.database.jdbc:ojdbc8:21.1.0.0', oracle: 'com.oracle.database.jdbc:ojdbc8:21.3.0.0',
mssql: 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8', mssql: 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8',
db2: 'com.ibm.db2:jcc:11.5.4.0', db2: 'com.ibm.db2:jcc:11.5.4.0',
hana: 'com.sap.cloud.db.jdbc:ngdbc:2.4.59', hana: 'com.sap.cloud.db.jdbc:ngdbc:2.4.59',

View File

@ -684,7 +684,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
try { try {
NativeQueryImpl query = new NativeQueryImpl( queryString, this ); NativeQueryImpl query = new NativeQueryImpl( queryString, this );
query.setComment( "dynamic native SQL query" ); if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native SQL query" );
}
applyQuerySettingsAndHints( query ); applyQuerySettingsAndHints( query );
return query; return query;
} }
@ -796,7 +798,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
if ( namedHqlDescriptor != null ) { if ( namedHqlDescriptor != null ) {
HqlQueryImplementor<T> query = namedHqlDescriptor.toQuery( this, resultType ); HqlQueryImplementor<T> query = namedHqlDescriptor.toQuery( this, resultType );
query.setComment( "dynamic HQL query" ); if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic HQL query" );
}
applyQuerySettingsAndHints( query ); applyQuerySettingsAndHints( query );
if ( namedHqlDescriptor.getLockOptions() != null ) { if ( namedHqlDescriptor.getLockOptions() != null ) {
query.setLockOptions( namedHqlDescriptor.getLockOptions() ); query.setLockOptions( namedHqlDescriptor.getLockOptions() );
@ -817,7 +821,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
else { else {
query = namedNativeDescriptor.toQuery( this, resultType ); query = namedNativeDescriptor.toQuery( this, resultType );
} }
query.setComment( "dynamic native SQL query" ); if ( StringHelper.isEmpty( query.getComment() ) ) {
query.setComment( "dynamic native SQL query" );
}
applyQuerySettingsAndHints( query ); applyQuerySettingsAndHints( query );
return query; return query;
} }

View File

@ -113,6 +113,7 @@ import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.proxy.HibernateProxyHelper; import org.hibernate.proxy.HibernateProxyHelper;
import org.hibernate.query.QueryLogging; import org.hibernate.query.QueryLogging;
import org.hibernate.query.hql.spi.HqlQueryImplementor; import org.hibernate.query.hql.spi.HqlQueryImplementor;
import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor; import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor;
@ -899,10 +900,11 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
// query implementations // query implementations
// first, handle StoredProcedureQuery // first, handle StoredProcedureQuery
final NamedObjectRepository namedObjectRepository = getQueryEngine().getNamedObjectRepository();
try { try {
final ProcedureCallImplementor unwrapped = query.unwrap( ProcedureCallImplementor.class ); final ProcedureCallImplementor unwrapped = query.unwrap( ProcedureCallImplementor.class );
if ( unwrapped != null ) { if ( unwrapped != null ) {
getQueryEngine().getNamedObjectRepository().registerCallableQueryMemento( namedObjectRepository.registerCallableQueryMemento(
name, name,
unwrapped.toMemento( name ) unwrapped.toMemento( name )
); );
@ -919,13 +921,14 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
if ( hibernateQuery != null ) { if ( hibernateQuery != null ) {
// create and register the proper NamedQueryDefinition... // create and register the proper NamedQueryDefinition...
if ( hibernateQuery instanceof NativeQueryImplementor ) { if ( hibernateQuery instanceof NativeQueryImplementor ) {
getQueryEngine().getNamedObjectRepository().registerNativeQueryMemento( namedObjectRepository.registerNativeQueryMemento(
name, name,
( (NativeQueryImplementor) hibernateQuery ).toMemento( name ) ( (NativeQueryImplementor) hibernateQuery ).toMemento( name )
); );
} }
else { else {
getQueryEngine().getNamedObjectRepository().registerHqlQueryMemento( namedObjectRepository.registerHqlQueryMemento(
name, name,
( ( HqlQueryImplementor ) hibernateQuery ).toMemento( name ) ( ( HqlQueryImplementor ) hibernateQuery ).toMemento( name )
); );

View File

@ -38,6 +38,7 @@ import org.hibernate.FetchMode;
import org.hibernate.Filter; import org.hibernate.Filter;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.JDBCException; import org.hibernate.JDBCException;
import org.hibernate.LazyInitializationException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.MappingException; import org.hibernate.MappingException;
@ -1609,8 +1610,9 @@ public abstract class AbstractEntityPersister
// for the collection to the just loaded collection // for the collection to the just loaded collection
final EntityEntry ownerEntry = persistenceContext.getEntry( entity ); final EntityEntry ownerEntry = persistenceContext.getEntry( entity );
if ( ownerEntry == null ) { if ( ownerEntry == null ) {
// not good // the entity is not in the session; it was probably deleted,
throw new AssertionFailure( // so we cannot load the collection anymore.
throw new LazyInitializationException(
"Could not locate EntityEntry for the collection owner in the PersistenceContext" "Could not locate EntityEntry for the collection owner in the PersistenceContext"
); );
} }

View File

@ -68,6 +68,7 @@ public class NamedObjectRepositoryImpl implements NamedObjectRepository {
@Override @Override
public synchronized void registerHqlQueryMemento(String name, NamedHqlQueryMemento descriptor) { public synchronized void registerHqlQueryMemento(String name, NamedHqlQueryMemento descriptor) {
hqlMementoMap.put( name, descriptor ); hqlMementoMap.put( name, descriptor );
sqlMementoMap.remove( name );
} }
@ -87,6 +88,7 @@ public class NamedObjectRepositoryImpl implements NamedObjectRepository {
@Override @Override
public synchronized void registerNativeQueryMemento(String name, NamedNativeQueryMemento descriptor) { public synchronized void registerNativeQueryMemento(String name, NamedNativeQueryMemento descriptor) {
sqlMementoMap.put( name, descriptor ); sqlMementoMap.put( name, descriptor );
hqlMementoMap.remove( name );
} }

View File

@ -123,6 +123,10 @@ public class ResultSetMappingImpl implements ResultSetMapping {
} }
} }
public String getMappingIdentifier(){
return mappingIdentifier;
}
@Override @Override
public void addAffectedTableNames(Set<String> affectedTableNames, SessionFactoryImplementor sessionFactory) { public void addAffectedTableNames(Set<String> affectedTableNames, SessionFactoryImplementor sessionFactory) {
if ( StringHelper.isEmpty( mappingIdentifier ) ) { if ( StringHelper.isEmpty( mappingIdentifier ) ) {

View File

@ -37,7 +37,6 @@ import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.QueryException; import org.hibernate.QueryException;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.engine.query.spi.NativeQueryInterpreter; import org.hibernate.engine.query.spi.NativeQueryInterpreter;
@ -145,8 +144,10 @@ public class NativeQueryImpl<R>
.getQueryEngine() .getQueryEngine()
.getNamedObjectRepository() .getNamedObjectRepository()
.getResultSetMappingMemento( memento.getResultMappingName() ); .getResultSetMappingMemento( memento.getResultMappingName() );
resultSetMappingMemento.resolve( resultSetMapping, querySpaceConsumer, context ); if ( resultSetMappingMemento != null ) {
return true; resultSetMappingMemento.resolve( resultSetMapping, querySpaceConsumer, context );
return true;
}
} }
if ( memento.getResultMappingClass() != null ) { if ( memento.getResultMappingClass() != null ) {
@ -376,7 +377,23 @@ public class NativeQueryImpl<R>
@Override @Override
public NamedNativeQueryMemento toMemento(String name) { public NamedNativeQueryMemento toMemento(String name) {
throw new NotYetImplementedFor6Exception( ); return new NamedNativeQueryMementoImpl(
name,
sqlString,
resultSetMapping.getMappingIdentifier(),
null,
querySpaces,
isCacheable(),
getCacheRegion(),
getCacheMode(),
getHibernateFlushMode(),
isReadOnly(),
getTimeout(),
getFetchSize(),
getComment(),
getHints()
);
} }
@Override @Override

View File

@ -454,7 +454,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
return getAssociatedEntityPersister( factory ).getIdentifierType(); return getAssociatedEntityPersister( factory ).getIdentifierType();
} }
protected EntityPersister getAssociatedEntityPersister(final SessionFactoryImplementor factory) { public EntityPersister getAssociatedEntityPersister(final SessionFactoryImplementor factory) {
final EntityPersister persister = associatedEntityPersister; final EntityPersister persister = associatedEntityPersister;
//The following branch implements a simple lazy-initialization, but rather than the canonical //The following branch implements a simple lazy-initialization, but rather than the canonical
//form it returns the local variable to avoid a second volatile read: associatedEntityPersister //form it returns the local variable to avoid a second volatile read: associatedEntityPersister
@ -469,7 +469,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
} }
protected final Object getIdentifier(Object value, SharedSessionContractImplementor session) throws HibernateException { protected final Object getIdentifier(Object value, SharedSessionContractImplementor session) throws HibernateException {
if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) { if ( isReferenceToIdentifierProperty() ) {
return ForeignKeys.getEntityIdentifierIfNotUnsaved( return ForeignKeys.getEntityIdentifierIfNotUnsaved(
getAssociatedEntityName(), getAssociatedEntityName(),
value, value,
@ -605,7 +605,7 @@ public abstract class EntityType extends AbstractType implements AssociationType
* or unique key property name. * or unique key property name.
*/ */
public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException { public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException {
if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) { if ( isReferenceToIdentifierProperty() ) {
return getIdentifierType( factory ); return getIdentifierType( factory );
} }
else { else {
@ -629,12 +629,14 @@ public abstract class EntityType extends AbstractType implements AssociationType
*/ */
public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory) public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory)
throws MappingException { throws MappingException {
if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) { return isReferenceToIdentifierProperty()
return factory.getIdentifierPropertyName( getAssociatedEntityName() ); ? factory.getIdentifierPropertyName( getAssociatedEntityName() )
} : uniqueKeyPropertyName;
else { }
return uniqueKeyPropertyName;
} public boolean isReferenceToIdentifierProperty() {
return isReferenceToPrimaryKey()
|| uniqueKeyPropertyName == null;
} }
/** /**

View File

@ -0,0 +1,222 @@
/*
* 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.query;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.test.Distributor;
import org.hibernate.jpa.test.Item;
import org.hibernate.jpa.test.Wallet;
import org.hibernate.query.hql.spi.NamedHqlQueryMemento;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
/**
* Tests for {@link javax.persistence.EntityManagerFactory#addNamedQuery} handling.
*
* @author Steve Ebersole
*/
@Jpa(
annotatedClasses = {
Item.class,
Distributor.class,
Wallet.class
}
)
public class AddNamedQueryTest {
@Test
public void basicTest(EntityManagerFactoryScope scope) {
// just making sure we can add one and that it is usable when we get it back
scope.inEntityManager(
entityManager -> {
Query query = entityManager.createQuery( "from Item" );
final String name = "myBasicItemQuery";
entityManager.getEntityManagerFactory().addNamedQuery( name, query );
Query query2 = entityManager.createNamedQuery( name );
query2.getResultList();
}
);
}
@Test
public void replaceTest(EntityManagerFactoryScope scope) {
scope.inEntityManager(
em -> {
final String name = "myReplaceItemQuery";
// create a jpql query
String sql = "from Item";
Query query = em.createQuery( sql );
query.setHint( "org.hibernate.comment", sql );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
assertEquals( sql, query.getHints().get( "org.hibernate.comment" ) );
assertEquals( 0, query.getResultList().size() );
// create a native query and replace the previous jpql
sql = "select * from Item";
query = em.createNativeQuery( sql, Item.class );
query.setHint( "org.hibernate.comment", sql );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
assertEquals( sql, query.getHints().get( "org.hibernate.comment" ) );
assertEquals( 0, query.getResultList().size() );
// define back a named query
sql = "from Item";
query = em.createQuery( sql );
query.setHint( "org.hibernate.comment", sql );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
assertEquals( sql, query.getHints().get( "org.hibernate.comment" ) );
assertEquals( 0, query.getResultList().size() );
}
);
}
@Test
public void testLockModeHandling(EntityManagerFactoryScope scope) {
final String name = "lock-mode-handling";
scope.inTransaction(
em -> {
Query q = em.createQuery( "from Item" );
assertEquals( LockModeType.NONE, q.getLockMode() );
q.setLockMode( LockModeType.OPTIMISTIC );
assertEquals( LockModeType.OPTIMISTIC, q.getLockMode() );
em.getEntityManagerFactory().addNamedQuery( name, q );
// first, lets check the underlying stored query def
SessionFactoryImplementor sfi = scope.getEntityManagerFactory()
.unwrap( SessionFactoryImplementor.class );
NamedHqlQueryMemento def = sfi.getQueryEngine()
.getNamedObjectRepository()
.getHqlQueryMemento( name );
assertEquals( LockMode.OPTIMISTIC, def.getLockOptions().getLockMode() );
// then lets create a query by name and check its setting
q = em.createNamedQuery( name );
assertEquals(
LockMode.OPTIMISTIC,
q.unwrap( org.hibernate.query.Query.class ).getLockOptions().getLockMode()
);
assertEquals( LockModeType.OPTIMISTIC, q.getLockMode() );
}
);
}
@Test
public void testFlushModeHandling(EntityManagerFactoryScope scope) {
final String name = "flush-mode-handling";
scope.inTransaction(
em -> {
Query q = em.createQuery( "from Item" );
assertEquals( FlushModeType.AUTO, q.getFlushMode() );
q.setFlushMode( FlushModeType.COMMIT );
assertEquals( FlushModeType.COMMIT, q.getFlushMode() );
em.getEntityManagerFactory().addNamedQuery( name, q );
// first, lets check the underlying stored query def
SessionFactoryImplementor sfi = scope.getEntityManagerFactory()
.unwrap( SessionFactoryImplementor.class );
NamedHqlQueryMemento def = sfi.getQueryEngine()
.getNamedObjectRepository()
.getHqlQueryMemento( name );
assertEquals( FlushMode.COMMIT, def.getFlushMode() );
// then lets create a query by name and check its setting
q = em.createNamedQuery( name );
assertEquals(
FlushMode.COMMIT,
q.unwrap( org.hibernate.query.Query.class ).getHibernateFlushMode()
);
assertEquals( FlushModeType.COMMIT, q.getFlushMode() );
}
);
}
@Test
public void testConfigValueHandling(EntityManagerFactoryScope scope) {
final String name = "itemJpaQueryWithLockModeAndHints";
scope.inTransaction(
em -> {
Query query = em.createNamedQuery( name );
org.hibernate.query.Query hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
//
// NOTE: here we check "query options" via the Hibernate contract (allowing nullness checking); see below for access via the JPA contract
assertNull( hibernateQuery.getQueryOptions().getFirstRow() );
assertNull( hibernateQuery.getQueryOptions().getMaxRows() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
// jpa timeout is in milliseconds, whereas Hibernate's is in seconds
assertEquals( (Integer) 3, hibernateQuery.getTimeout() );
query.setHint( QueryHints.HINT_TIMEOUT, 10 );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
//
// NOTE: here we check "query options" via the JPA contract
assertEquals( 0, hibernateQuery.getFirstResult() );
assertEquals( Integer.MAX_VALUE, hibernateQuery.getMaxResults() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
assertEquals( (Integer) 10, hibernateQuery.getTimeout() );
query.setHint( QueryHints.SPEC_HINT_TIMEOUT, 10000 );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
assertEquals( 0, hibernateQuery.getFirstResult() );
assertEquals( Integer.MAX_VALUE, hibernateQuery.getMaxResults() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
assertEquals( (Integer) 10, hibernateQuery.getTimeout() );
query.setFirstResult( 51 );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
assertEquals( 51, hibernateQuery.getFirstResult() );
assertEquals( Integer.MAX_VALUE, hibernateQuery.getMaxResults() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
assertEquals( (Integer) 10, hibernateQuery.getTimeout() );
}
);
}
}

View File

@ -0,0 +1,149 @@
/*
* 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.proxy;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import org.hibernate.LazyInitializationException;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
import org.hibernate.testing.bytecode.enhancement.EnhancementOptions;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
@TestForIssue(jiraKey = "HHH-14811")
@RunWith(BytecodeEnhancerRunner.class)
@EnhancementOptions(lazyLoading = true)
public class BytecodeEnhancedLazyLoadingOnDeletedEntityTest
extends BaseNonConfigCoreFunctionalTestCase {
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { AssociationOwner.class, AssociationNonOwner.class };
}
@After
public void tearDown() {
doInHibernate( this::sessionFactory, s -> {
s.createQuery( "delete from AOwner" ).executeUpdate();
s.createQuery( "delete from ANonOwner" ).executeUpdate();
} );
}
@Test
public void accessUnloadedLazyAssociationOnDeletedOwner() {
inTransaction( s -> {
AssociationOwner owner = new AssociationOwner();
owner.setId( 1 );
for ( int i = 0; i < 2; i++ ) {
AssociationNonOwner nonOwner = new AssociationNonOwner();
nonOwner.setId( i );
s.persist( nonOwner );
nonOwner.getOwners().add( owner );
owner.getNonOwners().add( nonOwner );
}
s.persist( owner );
} );
assertThatThrownBy( () -> inTransaction( session -> {
AssociationOwner owner = session.load( AssociationOwner.class, 1 );
session.delete( owner );
session.flush();
owner.getNonOwners().size();
} ) )
.isInstanceOf( LazyInitializationException.class )
.hasMessageContaining(
"Could not locate EntityEntry for the collection owner in the PersistenceContext" );
}
@Test
public void accessUnloadedLazyAssociationOnDeletedNonOwner() {
inTransaction( s -> {
AssociationNonOwner nonOwner = new AssociationNonOwner();
nonOwner.setId( 1 );
s.persist( nonOwner );
} );
assertThatThrownBy( () -> inTransaction( session -> {
AssociationNonOwner nonOwner = session.load( AssociationNonOwner.class, 1 );
session.delete( nonOwner );
session.flush();
nonOwner.getOwners().size();
} ) )
.isInstanceOf( LazyInitializationException.class )
.hasMessageContaining(
"Could not locate EntityEntry for the collection owner in the PersistenceContext" );
}
@Entity(name = "AOwner")
@Table
private static class AssociationOwner {
@Id
Integer id;
@ManyToMany(fetch = FetchType.LAZY)
List<AssociationNonOwner> nonOwners = new ArrayList<>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<AssociationNonOwner> getNonOwners() {
return nonOwners;
}
public void setNonOwners(
List<AssociationNonOwner> nonOwners) {
this.nonOwners = nonOwners;
}
}
@Entity(name = "ANonOwner")
@Table
private static class AssociationNonOwner {
@Id
Integer id;
@ManyToMany(mappedBy = "nonOwners", fetch = FetchType.LAZY)
List<AssociationOwner> owners = new ArrayList<>();
AssociationNonOwner() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<AssociationOwner> getOwners() {
return owners;
}
public void setOwners(List<AssociationOwner> owners) {
this.owners = owners;
}
}
}

View File

@ -1,178 +0,0 @@
/*
* 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.jpa.test.query;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.LockMode;
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.jpa.test.Distributor;
import org.hibernate.jpa.test.Item;
import org.hibernate.jpa.test.Wallet;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Tests for {@link javax.persistence.EntityManagerFactory#addNamedQuery} handling.
*
* @author Steve Ebersole
*/
public class AddNamedQueryTest extends BaseEntityManagerFunctionalTestCase {
@Override
public Class[] getAnnotatedClasses() {
return new Class[]{
Item.class,
Distributor.class,
Wallet.class
};
}
@Test
public void basicTest() {
// just making sure we can add one and that it is usable when we get it back
EntityManager em = getOrCreateEntityManager();
Query query = em.createQuery( "from Item" );
final String name = "myBasicItemQuery";
em.getEntityManagerFactory().addNamedQuery( name, query );
Query query2 = em.createNamedQuery( name );
query2.getResultList();
em.close();
}
@Test
public void testLockModeHandling() {
final String name = "lock-mode-handling";
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
Query q = em.createQuery( "from Item" );
assertEquals( LockModeType.NONE, q.getLockMode() );
q.setLockMode( LockModeType.OPTIMISTIC );
assertEquals( LockModeType.OPTIMISTIC, q.getLockMode() );
em.getEntityManagerFactory().addNamedQuery( name, q );
// first, lets check the underlying stored query def
SessionFactoryImplementor sfi = entityManagerFactory().unwrap( SessionFactoryImplementor.class );
NamedHqlQueryMementoImpl def = sfi.getNamedQueryRepository().getNamedQueryDefinition( name );
assertEquals( LockMode.OPTIMISTIC, def.getLockOptions().getLockMode() );
// then lets create a query by name and check its setting
q = em.createNamedQuery( name );
assertEquals( LockMode.OPTIMISTIC, q.unwrap( org.hibernate.query.Query.class ).getLockOptions().getLockMode() );
assertEquals( LockModeType.OPTIMISTIC, q.getLockMode() );
em.getTransaction().commit();
em.close();
}
@Test
public void testFlushModeHandling() {
final String name = "flush-mode-handling";
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
Query q = em.createQuery( "from Item" );
assertEquals( FlushModeType.AUTO, q.getFlushMode() );
q.setFlushMode( FlushModeType.COMMIT );
assertEquals( FlushModeType.COMMIT, q.getFlushMode() );
em.getEntityManagerFactory().addNamedQuery( name, q );
// first, lets check the underlying stored query def
SessionFactoryImplementor sfi = entityManagerFactory().unwrap( SessionFactoryImplementor.class );
NamedHqlQueryMementoImpl def = sfi.getNamedQueryRepository().getNamedQueryDefinition( name );
assertEquals( FlushMode.COMMIT, def.getFlushMode() );
// then lets create a query by name and check its setting
q = em.createNamedQuery( name );
assertEquals( FlushMode.COMMIT, q.unwrap( org.hibernate.query.Query.class ).getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, q.getFlushMode() );
em.getTransaction().commit();
em.close();
}
@Test
public void testConfigValueHandling() {
final String name = "itemJpaQueryWithLockModeAndHints";
EntityManager em = getOrCreateEntityManager();
em.getTransaction().begin();
Query query = em.createNamedQuery( name );
org.hibernate.query.Query hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
//
// NOTE: here we check "query options" via the Hibernate contract (allowing nullness checking); see below for access via the JPA contract
assertNull( hibernateQuery.getQueryOptions().getFirstRow() );
assertNull( hibernateQuery.getQueryOptions().getMaxRows() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
// jpa timeout is in milliseconds, whereas Hibernate's is in seconds
assertEquals( (Integer) 3, hibernateQuery.getTimeout() );
query.setHint( QueryHints.HINT_TIMEOUT, 10 );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
//
// NOTE: here we check "query options" via the JPA contract
assertEquals( 0, hibernateQuery.getFirstResult() );
assertEquals( Integer.MAX_VALUE, hibernateQuery.getMaxResults() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
assertEquals( (Integer) 10, hibernateQuery.getTimeout() );
query.setHint( QueryHints.SPEC_HINT_TIMEOUT, 10000 );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
assertEquals( 0, hibernateQuery.getFirstResult() );
assertEquals( Integer.MAX_VALUE, hibernateQuery.getMaxResults() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
assertEquals( (Integer) 10, hibernateQuery.getTimeout() );
query.setFirstResult( 51 );
em.getEntityManagerFactory().addNamedQuery( name, query );
query = em.createNamedQuery( name );
hibernateQuery = (org.hibernate.query.Query) query;
// assert the state of the query config settings based on the initial named query
assertEquals( 51, hibernateQuery.getFirstResult() );
assertEquals( Integer.MAX_VALUE, hibernateQuery.getMaxResults() );
assertEquals( FlushMode.MANUAL, hibernateQuery.getHibernateFlushMode() );
assertEquals( FlushModeType.COMMIT, hibernateQuery.getFlushMode() );
assertEquals( CacheMode.IGNORE, hibernateQuery.getCacheMode() );
assertEquals( LockMode.PESSIMISTIC_WRITE, hibernateQuery.getLockOptions().getLockMode() );
assertEquals( (Integer) 10, hibernateQuery.getTimeout() );
em.getTransaction().commit();
em.close();
}
}