/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* 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.ogm.backendtck.batchfetching;
import static org.fest.assertions.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.List;
import java.util.Map;
import org.fest.assertions.Assertions;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.ogm.cfg.OgmProperties;
import org.hibernate.ogm.dialect.impl.GridDialects;
import org.hibernate.ogm.dialect.multiget.spi.MultigetGridDialect;
import org.hibernate.ogm.dialect.spi.GridDialect;
import org.hibernate.ogm.utils.InvokedOperationsLoggingDialect;
import org.hibernate.ogm.utils.OgmTestCase;
import org.hibernate.ogm.utils.TestForIssue;
import org.hibernate.stat.Statistics;
import org.junit.Test;
/**
* @author Emmanuel Bernard emmanuel@hibernate.org
*/
public class BatchFetchingTest extends OgmTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Tower.class, Floor.class, CondominiumBuilding.class, Condominium.class };
}
@Test
public void testLoadSeveralFloorsByBatch() throws Exception {
Session session = openSession();
Tower tower = prepareTower( session );
session.clear();
session.beginTransaction();
for ( Floor currentFloor : tower.getFloors() ) {
// load proxies
assertFalse( Hibernate.isInitialized( session.load( Floor.class, currentFloor.getId() ) ) );
}
Statistics statistics = session.getSessionFactory().getStatistics();
statistics.setStatisticsEnabled( true );
statistics.clear();
assertEquals( 0, statistics.getEntityStatistics( Floor.class.getName() ).getFetchCount() );
getOperationsLogger().reset();
for ( Floor currentFloor : tower.getFloors() ) {
// load proxies
Object entity = session.load( Floor.class, currentFloor.getId() );
Hibernate.initialize( entity );
assertTrue( Hibernate.isInitialized( entity ) );
}
// if a multiget, we load both entities as one go, otherwise we don't
int fetchSize = isMultigetDialect() ? 1 : 2;
assertEquals( fetchSize, statistics.getEntityStatistics( Floor.class.getName() ).getFetchCount() );
if ( isMultigetDialect() ) {
assertThat( getOperations() ).containsExactly(
"getTuples"
);
}
else {
assertThat( getOperations() ).containsExactly(
"getTuple",
"getTuple"
);
}
session.getTransaction().commit();
cleanTower( session, tower );
session.close();
}
@Test
public void testLoadSeveralFloorsFromTower() throws Exception {
Session session = openSession();
Tower tower = prepareTower( session );
session.clear();
// now read the tower and its floors to detect 1+n patterns;
session.beginTransaction();
tower = session.get( Tower.class, tower.getId() );
Statistics statistics = session.getSessionFactory().getStatistics();
statistics.setStatisticsEnabled( true );
statistics.clear();
assertEquals( 0, statistics.getEntityStatistics( Floor.class.getName() ).getFetchCount() );
getOperationsLogger().reset();
Assertions.assertThat( tower.getFloors() ).hasSize( 2 );
// if a multiget, we load both entities as one go, otherwise we don't
int fetchSize = isMultigetDialect() ? 1 : 2;
assertEquals( fetchSize, statistics.getEntityStatistics( Floor.class.getName() ).getFetchCount() );
session.getTransaction().commit();
if ( isMultigetDialect() ) {
assertThat( getOperations() ).containsExactly(
"getAssociation",
"getTuples"
);
}
else {
assertThat( getOperations() ).containsExactly(
"getAssociation",
"getTuple",
"getTuple"
);
}
cleanTower( session, tower );
session.close();
}
@Test
@TestForIssue(jiraKey = "OGM-945")
public void testMultigetIsAppliedWithoutExplicitBatchSizeGiven() throws Exception {
Session session = openSession();
prepareCondoBuilding( session );
session.clear();
// now read the condo building and its appartments to detect 1+n patterns;
session.beginTransaction();
CondominiumBuilding condoBuilding = session.get( CondominiumBuilding.class, "cb-1" );
Statistics statistics = session.getSessionFactory().getStatistics();
statistics.setStatisticsEnabled( true );
statistics.clear();
assertEquals( 0, statistics.getEntityStatistics( Condominium.class.getName() ).getFetchCount() );
getOperationsLogger().reset();
Assertions.assertThat( condoBuilding.getCondominiums() ).hasSize( 3 );
// if a multiget, we load all entities as one go, otherwise we don't
int fetchSize = isMultigetDialect() ? 1 : 3;
assertEquals( fetchSize, statistics.getEntityStatistics( Condominium.class.getName() ).getFetchCount() );
session.getTransaction().commit();
if ( isMultigetDialect() ) {
assertThat( getOperations() ).containsExactly(
"getAssociation",
"getTuples"
);
}
else {
assertThat( getOperations() ).containsExactly(
"getAssociation",
"getTuple",
"getTuple",
"getTuple"
);
}
cleanCondoBuilding( session );
session.close();
}
private void cleanTower(Session session, Tower tower) {
session.beginTransaction();
session.delete( session.get( Tower.class, tower.getId() ) );
for ( Floor currentFloor : tower.getFloors() ) {
session.delete( session.get( Floor.class, currentFloor.getId() ) );
}
session.delete( new CondominiumBuilding( "cb-1" ) );
session.getTransaction().commit();
}
private Tower prepareTower(Session session) {
session.beginTransaction();
Tower tower = new Tower();
tower.setName( "Pise" );
Floor floor = new Floor();
floor.setLevel( 0 );
tower.getFloors().add( floor );
floor = new Floor();
floor.setLevel( 1 );
tower.getFloors().add( floor );
session.persist( tower );
session.getTransaction().commit();
return tower;
}
private void cleanCondoBuilding(Session session) {
session.beginTransaction();
session.delete( session.get( CondominiumBuilding.class, "cb-1" ) );
session.getTransaction().commit();
}
private CondominiumBuilding prepareCondoBuilding(Session session) {
session.beginTransaction();
CondominiumBuilding condoBuilding = new CondominiumBuilding();
condoBuilding.setId( "cb-1" );
condoBuilding.getCondominiums().add( new Condominium( "condo-1", 110 ) );
condoBuilding.getCondominiums().add( new Condominium( "condo-2", 90 ) );
condoBuilding.getCondominiums().add( new Condominium( "condo-3", 135 ) );
session.persist( condoBuilding );
session.getTransaction().commit();
return condoBuilding;
}
private boolean isMultigetDialect() {
GridDialect gridDialect = getSessionFactory().getServiceRegistry().getService( GridDialect.class );
return GridDialects.hasFacet( gridDialect, MultigetGridDialect.class );
}
@Override
protected void configure(Map<String, Object> cfg) {
cfg.put( OgmProperties.GRID_DIALECT, InvokedOperationsLoggingDialect.class );
}
private InvokedOperationsLoggingDialect getOperationsLogger() {
GridDialect gridDialect = getSessionFactory().getServiceRegistry().getService( GridDialect.class );
InvokedOperationsLoggingDialect invocationLogger = GridDialects.getDelegateOrNull(
gridDialect,
InvokedOperationsLoggingDialect.class
);
return invocationLogger;
}
private List<String> getOperations() {
return getOperationsLogger().getOperations();
}
}