HHH-8487 - Auto-flush on JPA native SQL query
This commit is contained in:
parent
05dcb8f5c1
commit
c6fbd4be4c
|
@ -51,8 +51,7 @@ import org.hibernate.jpa.graph.internal.EntityGraphImpl;
|
||||||
*/
|
*/
|
||||||
public class EntityManagerImpl extends AbstractEntityManagerImpl implements SessionOwner {
|
public class EntityManagerImpl extends AbstractEntityManagerImpl implements SessionOwner {
|
||||||
|
|
||||||
public static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
|
public static final EntityManagerMessageLogger LOG = HEMLogging.messageLogger( EntityManagerImpl.class.getName() );
|
||||||
EntityManagerImpl.class.getName());
|
|
||||||
|
|
||||||
protected Session session;
|
protected Session session;
|
||||||
protected boolean open;
|
protected boolean open;
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.SQLQuery;
|
||||||
import org.hibernate.TypeMismatchException;
|
import org.hibernate.TypeMismatchException;
|
||||||
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
||||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||||
|
@ -382,6 +383,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
@SuppressWarnings({ "unchecked", "RedundantCast" })
|
@SuppressWarnings({ "unchecked", "RedundantCast" })
|
||||||
public List<X> getResultList() {
|
public List<X> getResultList() {
|
||||||
getEntityManager().checkOpen( true );
|
getEntityManager().checkOpen( true );
|
||||||
|
beforeQuery();
|
||||||
try {
|
try {
|
||||||
return query.list();
|
return query.list();
|
||||||
}
|
}
|
||||||
|
@ -396,10 +398,33 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For JPA native SQL queries, we may need to perform a flush before executing the query.
|
||||||
|
*/
|
||||||
|
private void beforeQuery() {
|
||||||
|
final org.hibernate.Query query = getHibernateQuery();
|
||||||
|
if ( ! SQLQuery.class.isInstance( query ) ) {
|
||||||
|
// this need only exists for native SQL queries, not JPQL or Criteria queries (both of which do
|
||||||
|
// partial auto flushing already).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final SQLQuery sqlQuery = (SQLQuery) query;
|
||||||
|
if ( sqlQuery.getSynchronizedQuerySpaces() != null && ! sqlQuery.getSynchronizedQuerySpaces().isEmpty() ) {
|
||||||
|
// The application defined query spaces on the Hibernate native SQLQuery which means the query will already
|
||||||
|
// perform a partial flush according to the defined query spaces, no need to do a full flush.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise we need to flush
|
||||||
|
getEntityManager().flush();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked", "RedundantCast" })
|
@SuppressWarnings({ "unchecked", "RedundantCast" })
|
||||||
public X getSingleResult() {
|
public X getSingleResult() {
|
||||||
getEntityManager().checkOpen( true );
|
getEntityManager().checkOpen( true );
|
||||||
|
beforeQuery();
|
||||||
try {
|
try {
|
||||||
final List<X> result = query.list();
|
final List<X> result = query.list();
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.jpa.test.metamodel.AbstractMetamodelSpecificTest;
|
import org.hibernate.jpa.test.metamodel.AbstractMetamodelSpecificTest;
|
||||||
|
import org.hibernate.jpa.test.metamodel.CreditCard;
|
||||||
|
import org.hibernate.jpa.test.metamodel.CreditCard_;
|
||||||
import org.hibernate.jpa.test.metamodel.Customer_;
|
import org.hibernate.jpa.test.metamodel.Customer_;
|
||||||
import org.hibernate.jpa.test.metamodel.Order;
|
import org.hibernate.jpa.test.metamodel.Order;
|
||||||
import org.hibernate.jpa.test.metamodel.Order_;
|
import org.hibernate.jpa.test.metamodel.Order_;
|
||||||
|
@ -282,4 +284,28 @@ public class PredicateTest extends AbstractMetamodelSpecificTest {
|
||||||
em.close();
|
em.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExplicitBuilderBooleanHandling() {
|
||||||
|
// just checking syntax of the resulting query
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
// note : these may fail on various matrix db jobs depending on how the dialect handles booleans
|
||||||
|
{
|
||||||
|
CriteriaQuery<CreditCard> criteriaQuery = builder.createQuery( CreditCard.class );
|
||||||
|
Root<CreditCard> root = criteriaQuery.from( CreditCard.class );
|
||||||
|
criteriaQuery.where( builder.isFalse( root.get( CreditCard_.approved ) ) );
|
||||||
|
em.createQuery( criteriaQuery ).getResultList();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
CriteriaQuery<Order> criteriaQuery = builder.createQuery( Order.class );
|
||||||
|
Root<Order> root = criteriaQuery.from( Order.class );
|
||||||
|
criteriaQuery.where( builder.isFalse( root.get( Order_.creditCard ).get( CreditCard_.approved ) ) );
|
||||||
|
em.createQuery( criteriaQuery ).getResultList();
|
||||||
|
}
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
import javax.persistence.Query;
|
import javax.persistence.Query;
|
||||||
|
@ -38,10 +39,15 @@ import javax.persistence.Tuple;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
import org.hibernate.jpa.test.Distributor;
|
import org.hibernate.jpa.test.Distributor;
|
||||||
import org.hibernate.jpa.test.Item;
|
import org.hibernate.jpa.test.Item;
|
||||||
import org.hibernate.jpa.test.Wallet;
|
import org.hibernate.jpa.test.Wallet;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
|
||||||
|
@ -56,6 +62,22 @@ import static org.junit.Assert.fail;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
@Override
|
||||||
|
public Class[] getAnnotatedClasses() {
|
||||||
|
return new Class[] {
|
||||||
|
Item.class,
|
||||||
|
Distributor.class,
|
||||||
|
Wallet.class
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void addConfigOptions(Map options) {
|
||||||
|
super.addConfigOptions( options );
|
||||||
|
options.put( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue( jiraKey = "HHH-7192" )
|
@TestForIssue( jiraKey = "HHH-7192" )
|
||||||
public void testTypedManipulationQueryError() {
|
public void testTypedManipulationQueryError() {
|
||||||
|
@ -300,8 +322,13 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
assertTrue( em.contains( item ) );
|
assertTrue( em.contains( item ) );
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
Statistics stats = em.getEntityManagerFactory().unwrap( SessionFactoryImplementor.class ).getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
assertEquals( 0, stats.getFlushCount() );
|
||||||
|
|
||||||
em.getTransaction().begin();
|
em.getTransaction().begin();
|
||||||
item = (Item) em.createNativeQuery( "select * from Item", Item.class ).getSingleResult();
|
item = (Item) em.createNativeQuery( "select * from Item", Item.class ).getSingleResult();
|
||||||
|
assertEquals( 1, stats.getFlushCount() );
|
||||||
assertNotNull( item );
|
assertNotNull( item );
|
||||||
assertEquals( "Micro$oft mouse", item.getDescr() );
|
assertEquals( "Micro$oft mouse", item.getDescr() );
|
||||||
em.remove( item );
|
em.remove( item );
|
||||||
|
@ -590,14 +617,18 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
//success
|
//success
|
||||||
}
|
}
|
||||||
assertTrue( "thrown IllegalArgumentException should of caused transaction to be marked for rollback only",
|
assertTrue(
|
||||||
true == em.getTransaction().getRollbackOnly() );
|
"thrown IllegalArgumentException should of caused transaction to be marked for rollback only",
|
||||||
|
true == em.getTransaction().getRollbackOnly()
|
||||||
|
);
|
||||||
em.getTransaction().rollback(); // HHH-8442 changed to rollback since thrown ISE causes
|
em.getTransaction().rollback(); // HHH-8442 changed to rollback since thrown ISE causes
|
||||||
// transaction to be marked for rollback only.
|
// transaction to be marked for rollback only.
|
||||||
// No need to remove entity since it was rolled back.
|
// No need to remove entity since it was rolled back.
|
||||||
|
|
||||||
assertNull( "entity should not of been saved to database since IllegalArgumentException should of" +
|
assertNull(
|
||||||
"caused transaction to be marked for rollback only", em.find(Item.class, item.getName()));
|
"entity should not of been saved to database since IllegalArgumentException should of" +
|
||||||
|
"caused transaction to be marked for rollback only", em.find( Item.class, item.getName() )
|
||||||
|
);
|
||||||
em.close();
|
em.close();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -652,13 +683,4 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
em.close();
|
em.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class[] getAnnotatedClasses() {
|
|
||||||
return new Class[]{
|
|
||||||
Item.class,
|
|
||||||
Distributor.class,
|
|
||||||
Wallet.class
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue