HHH-7841 - Redesign Loader
This commit is contained in:
parent
1337d36a79
commit
dfe33ffa1a
|
@ -31,6 +31,7 @@ import org.hibernate.engine.FetchStrategy;
|
|||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.loader.plan.internal.LoadPlanBuildingHelper;
|
||||
import org.hibernate.loader.plan.spi.build.LoadPlanBuildingContext;
|
||||
import org.hibernate.loader.spi.ResultSetProcessingContext;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
@ -78,7 +79,7 @@ public class CompositeFetch extends AbstractSingularAttributeFetch {
|
|||
@Override
|
||||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition, LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
return LoadPlanBuildingHelper.buildStandardCompositeFetch( this, attributeDefinition, loadPlanBuildingContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -111,6 +111,7 @@ import org.hibernate.metamodel.relational.DerivedValue;
|
|||
import org.hibernate.metamodel.relational.Value;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AttributeSource;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.EncapsulatedEntityIdentifierDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
|
@ -130,6 +131,7 @@ import org.hibernate.sql.Update;
|
|||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.Type;
|
||||
|
@ -5120,13 +5122,13 @@ public abstract class AbstractEntityPersister
|
|||
final Type idType = getIdentifierType();
|
||||
|
||||
if ( !idType.isComponentType() ) {
|
||||
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
|
||||
entityIdentifierDefinition = buildSimpleEncapsulatedIdentifierDefinition();
|
||||
return;
|
||||
}
|
||||
|
||||
final CompositeType cidType = (CompositeType) idType;
|
||||
if ( !cidType.isEmbedded() ) {
|
||||
entityIdentifierDefinition = buildEncapsulatedIdentifierDefinition();
|
||||
entityIdentifierDefinition = buildEncapsulatedCompositeIdentifierDefinition();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -5155,7 +5157,7 @@ public abstract class AbstractEntityPersister
|
|||
};
|
||||
}
|
||||
|
||||
private EntityIdentifierDefinition buildEncapsulatedIdentifierDefinition() {
|
||||
private EntityIdentifierDefinition buildSimpleEncapsulatedIdentifierDefinition() {
|
||||
final AttributeDefinition simpleIdentifierAttributeAdapter = new AttributeDefinition() {
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -5196,6 +5198,55 @@ public abstract class AbstractEntityPersister
|
|||
};
|
||||
}
|
||||
|
||||
private EntityIdentifierDefinition buildEncapsulatedCompositeIdentifierDefinition() {
|
||||
final CompositionDefinition compositeIdentifierAttributeAdapter = new CompositionDefinition() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return entityMetamodel.getIdentifierProperty().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return entityMetamodel.getIdentifierProperty().getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeSource getSource() {
|
||||
return AbstractEntityPersister.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<identifier-property:" + getName() + ">";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<AttributeDefinition> getAttributes() {
|
||||
ComponentType componentType = (ComponentType) getType();
|
||||
//for ( Type type : componentType.getSubtypes() ) {
|
||||
throw new NotYetImplementedException( "cannot create sub-attribute definitions for a ComponentType yet." );
|
||||
//}
|
||||
}
|
||||
};
|
||||
|
||||
return new EncapsulatedEntityIdentifierDefinition() {
|
||||
@Override
|
||||
public AttributeDefinition getAttributeDefinition() {
|
||||
return compositeIdentifierAttributeAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncapsulated() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityDefinition getEntityDefinition() {
|
||||
return AbstractEntityPersister.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void collectAttributeDefinitions() {
|
||||
// todo : leverage the attribute definitions housed on EntityMetamodel
|
||||
// for that to work, we'd have to be able to walk our super entity persister(s)
|
||||
|
|
|
@ -72,21 +72,21 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
|
|||
public Iterator<AttributeDefinition> iterator() {
|
||||
return new Iterator<AttributeDefinition>() {
|
||||
private final int numberOfAttributes = getType().getSubtypes().length;
|
||||
private int currentAttributeNumber = 0;
|
||||
private int currentSubAttributeNumber = 0;
|
||||
private int currentColumnPosition = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return currentAttributeNumber < numberOfAttributes;
|
||||
return currentSubAttributeNumber < numberOfAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeDefinition next() {
|
||||
final int attributeNumber = currentAttributeNumber;
|
||||
currentAttributeNumber++;
|
||||
final int subAttributeNumber = currentSubAttributeNumber;
|
||||
currentSubAttributeNumber++;
|
||||
|
||||
final String name = getType().getPropertyNames()[attributeNumber];
|
||||
final Type type = getType().getSubtypes()[attributeNumber];
|
||||
final String name = getType().getPropertyNames()[subAttributeNumber];
|
||||
final Type type = getType().getSubtypes()[subAttributeNumber];
|
||||
|
||||
int columnPosition = currentColumnPosition;
|
||||
currentColumnPosition += type.getColumnSpan( sessionFactory() );
|
||||
|
@ -122,7 +122,7 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
|
|||
return new CompositeBasedAssociationAttribute(
|
||||
AbstractCompositionDefinition.this,
|
||||
sessionFactory(),
|
||||
currentAttributeNumber,
|
||||
subAttributeNumber,
|
||||
name,
|
||||
(AssociationType) type,
|
||||
new BaselineAttributeInformation.Builder()
|
||||
|
@ -130,11 +130,11 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
|
|||
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||
.setNullable( getType().getPropertyNullability()[subAttributeNumber] )
|
||||
.setDirtyCheckable( true )
|
||||
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||
.setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( subAttributeNumber ) )
|
||||
.createInformation(),
|
||||
AbstractCompositionDefinition.this.attributeNumber(),
|
||||
associationKey
|
||||
|
@ -144,7 +144,7 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
|
|||
return new CompositionBasedCompositionAttribute(
|
||||
AbstractCompositionDefinition.this,
|
||||
sessionFactory(),
|
||||
currentAttributeNumber,
|
||||
subAttributeNumber,
|
||||
name,
|
||||
(CompositeType) type,
|
||||
new BaselineAttributeInformation.Builder()
|
||||
|
@ -152,11 +152,11 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
|
|||
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||
.setNullable( getType().getPropertyNullability()[subAttributeNumber] )
|
||||
.setDirtyCheckable( true )
|
||||
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||
.setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( subAttributeNumber ) )
|
||||
.createInformation()
|
||||
);
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
|
|||
return new CompositeBasedBasicAttribute(
|
||||
AbstractCompositionDefinition.this,
|
||||
sessionFactory(),
|
||||
currentAttributeNumber,
|
||||
subAttributeNumber,
|
||||
name,
|
||||
type,
|
||||
new BaselineAttributeInformation.Builder()
|
||||
|
@ -172,11 +172,11 @@ public abstract class AbstractCompositionDefinition extends AbstractNonIdentifie
|
|||
.setUpdateable( AbstractCompositionDefinition.this.isUpdateable() )
|
||||
.setInsertGenerated( AbstractCompositionDefinition.this.isInsertGenerated() )
|
||||
.setUpdateGenerated( AbstractCompositionDefinition.this.isUpdateGenerated() )
|
||||
.setNullable( getType().getPropertyNullability()[currentAttributeNumber] )
|
||||
.setNullable( getType().getPropertyNullability()[subAttributeNumber] )
|
||||
.setDirtyCheckable( true )
|
||||
.setVersionable( AbstractCompositionDefinition.this.isVersionable() )
|
||||
.setCascadeStyle( getType().getCascadeStyle( currentAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( currentAttributeNumber ) )
|
||||
.setCascadeStyle( getType().getCascadeStyle( subAttributeNumber ) )
|
||||
.setFetchMode( getType().getFetchMode( subAttributeNumber ) )
|
||||
.createInformation()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.loader.internal.EntityLoadQueryBuilderImpl;
|
||||
import org.hibernate.loader.internal.LoadQueryAliasResolutionContextImpl;
|
||||
import org.hibernate.loader.internal.ResultSetProcessorImpl;
|
||||
import org.hibernate.loader.plan.internal.SingleRootReturnLoadPlanBuilderStrategy;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.build.LoadPlanBuilder;
|
||||
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
|
||||
import org.hibernate.loader.spi.NamedParameterContext;
|
||||
import org.hibernate.loader.spi.NoOpLoadPlanAdvisor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.junit4.ExtraAssertions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class EncapsulatedCompositeAttributeResultSetProcessorTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Person.class, Customer.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNestedCompositeAttributeProcessing() throws Exception {
|
||||
// create some test data
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
Person person = new Person();
|
||||
person.id = 1;
|
||||
person.name = "Joe Blow";
|
||||
person.address = new Address();
|
||||
person.address.address1 = "1313 Mockingbird Lane";
|
||||
person.address.city = "Pleasantville";
|
||||
person.address.country = "USA";
|
||||
AddressType addressType = new AddressType();
|
||||
addressType.typeName = "snail mail";
|
||||
person.address.type = addressType;
|
||||
session.save( person );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
Person personGotten = (Person) session.get( Person.class, person.id );
|
||||
assertEquals( person.id, personGotten.id );
|
||||
assertEquals( person.address.address1, personGotten.address.address1 );
|
||||
assertEquals( person.address.city, personGotten.address.city );
|
||||
assertEquals( person.address.country, personGotten.address.country );
|
||||
assertEquals( person.address.type.typeName, personGotten.address.type.typeName );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
List results = getResults( sessionFactory().getEntityPersister( Person.class.getName() ) );
|
||||
assertEquals( 1, results.size() );
|
||||
Object result = results.get( 0 );
|
||||
assertNotNull( result );
|
||||
|
||||
Person personWork = ExtraAssertions.assertTyping( Person.class, result );
|
||||
assertEquals( person.id, personWork.id );
|
||||
assertEquals( person.address.address1, personWork.address.address1 );
|
||||
assertEquals( person.address.city, personWork.address.city );
|
||||
assertEquals( person.address.country, personWork.address.country );
|
||||
assertEquals( person.address.type.typeName, personGotten.address.type.typeName );
|
||||
|
||||
// clean up test data
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.createQuery( "delete Person" ).executeUpdate();
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
/*
|
||||
@Test
|
||||
public void testNestedCompositeElementCollectionProcessing() throws Exception {
|
||||
// create some test data
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
Customer customer = new Customer();
|
||||
customer.id = 1L;
|
||||
Investment investment1 = new Investment();
|
||||
investment1.description = "stock";
|
||||
investment1.date = new Date();
|
||||
investment1.monetaryAmount = new MonetaryAmount();
|
||||
investment1.monetaryAmount.currency = MonetaryAmount.CurrencyCode.USD;
|
||||
investment1.monetaryAmount.amount = BigDecimal.valueOf( 1234, 2 );
|
||||
Investment investment2 = new Investment();
|
||||
investment2.description = "bond";
|
||||
investment2.date = new Date();
|
||||
investment2.monetaryAmount = new MonetaryAmount();
|
||||
investment2.monetaryAmount.currency = MonetaryAmount.CurrencyCode.EUR;
|
||||
investment2.monetaryAmount.amount = BigDecimal.valueOf( 98176, 1 );
|
||||
customer.investments.add( investment1 );
|
||||
customer.investments.add( investment2 );
|
||||
session.save( customer );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
Customer customerGotten = (Customer) session.get( Customer.class, customer.id );
|
||||
assertEquals( customer.id, customerGotten.id );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
List results = getResults( sessionFactory().getEntityPersister( Customer.class.getName() ) );
|
||||
|
||||
assertEquals( 2, results.size() );
|
||||
assertSame( results.get( 0 ), results.get( 1 ) );
|
||||
Object result = results.get( 0 );
|
||||
assertNotNull( result );
|
||||
|
||||
Customer customerWork = ExtraAssertions.assertTyping( Customer.class, result );
|
||||
|
||||
// clean up test data
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.createQuery( "delete Customer" ).executeUpdate();
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
*/
|
||||
|
||||
private List<?> getResults(EntityPersister entityPersister ) {
|
||||
final SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
|
||||
sessionFactory(),
|
||||
LoadQueryInfluencers.NONE
|
||||
);
|
||||
final LoadPlan plan = LoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister );
|
||||
final LoadQueryAliasResolutionContext aliasResolutionContext =
|
||||
new LoadQueryAliasResolutionContextImpl(
|
||||
sessionFactory(),
|
||||
0,
|
||||
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
|
||||
);
|
||||
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
|
||||
LoadQueryInfluencers.NONE,
|
||||
plan
|
||||
);
|
||||
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
|
||||
|
||||
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
|
||||
final List results = new ArrayList();
|
||||
|
||||
final Session workSession = openSession();
|
||||
workSession.beginTransaction();
|
||||
workSession.doWork(
|
||||
new Work() {
|
||||
@Override
|
||||
public void execute(Connection connection) throws SQLException {
|
||||
PreparedStatement ps = connection.prepareStatement( sql );
|
||||
ps.setInt( 1, 1 );
|
||||
ResultSet resultSet = ps.executeQuery();
|
||||
results.addAll(
|
||||
resultSetProcessor.extractResults(
|
||||
NoOpLoadPlanAdvisor.INSTANCE,
|
||||
resultSet,
|
||||
(SessionImplementor) workSession,
|
||||
new QueryParameters(),
|
||||
new NamedParameterContext() {
|
||||
@Override
|
||||
public int[] getNamedParameterLocations(String name) {
|
||||
return new int[0];
|
||||
}
|
||||
},
|
||||
aliasResolutionContext,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
)
|
||||
);
|
||||
resultSet.close();
|
||||
ps.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
workSession.getTransaction().commit();
|
||||
workSession.close();
|
||||
return results;
|
||||
}
|
||||
|
||||
@Entity( name = "Person" )
|
||||
public static class Person implements Serializable {
|
||||
@Id
|
||||
Integer id;
|
||||
String name;
|
||||
|
||||
@Embedded
|
||||
Address address;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Address implements Serializable {
|
||||
String address1;
|
||||
String city;
|
||||
String country;
|
||||
AddressType type;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class AddressType {
|
||||
String typeName;
|
||||
}
|
||||
|
||||
@Entity( name = "Customer" )
|
||||
public static class Customer {
|
||||
private Long id;
|
||||
private List<Investment> investments = new ArrayList<Investment>();
|
||||
|
||||
@Id
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
public List<Investment> getInvestments() {
|
||||
return investments;
|
||||
}
|
||||
public void setInvestments(List<Investment> investments) {
|
||||
this.investments = investments;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Investment {
|
||||
private MonetaryAmount monetaryAmount;
|
||||
private String description;
|
||||
private Date date;
|
||||
|
||||
@Embedded
|
||||
public MonetaryAmount getMonetaryAmount() {
|
||||
return monetaryAmount;
|
||||
}
|
||||
public void setMonetaryAmount(MonetaryAmount monetaryAmount) {
|
||||
this.monetaryAmount = monetaryAmount;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class MonetaryAmount {
|
||||
public static enum CurrencyCode {
|
||||
USD,
|
||||
EUR
|
||||
}
|
||||
private BigDecimal amount;
|
||||
@Column(length = 3)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private CurrencyCode currency;
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public CurrencyCode getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
public void setCurrency(CurrencyCode currency) {
|
||||
this.currency = currency;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ import static org.junit.Assert.assertTrue;
|
|||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class EntityWithCollectionResultSetProcessorTest extends BaseCoreFunctionalTestCase {
|
||||
public class EntityWithNonLazyCollectionResultSetProcessorTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.loader;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.jdbc.Work;
|
||||
import org.hibernate.loader.internal.EntityLoadQueryBuilderImpl;
|
||||
import org.hibernate.loader.internal.LoadQueryAliasResolutionContextImpl;
|
||||
import org.hibernate.loader.internal.ResultSetProcessorImpl;
|
||||
import org.hibernate.loader.plan.internal.SingleRootReturnLoadPlanBuilderStrategy;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.loader.plan.spi.build.LoadPlanBuilder;
|
||||
import org.hibernate.loader.spi.LoadQueryAliasResolutionContext;
|
||||
import org.hibernate.loader.spi.NamedParameterContext;
|
||||
import org.hibernate.loader.spi.NoOpLoadPlanAdvisor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.junit4.ExtraAssertions;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class EntityWithNonLazyOneToManyListResultSetProcessorTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Poster.class, Message.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEntityWithList() throws Exception {
|
||||
final EntityPersister entityPersister = sessionFactory().getEntityPersister( Poster.class.getName() );
|
||||
|
||||
// create some test data
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
Poster poster = new Poster();
|
||||
poster.pid = 0;
|
||||
poster.name = "John Doe";
|
||||
Message message1 = new Message();
|
||||
message1.mid = 1;
|
||||
message1.msgTxt = "Howdy!";
|
||||
message1.poster = poster;
|
||||
poster.messages.add( message1 );
|
||||
Message message2 = new Message();
|
||||
message2.mid = 2;
|
||||
message2.msgTxt = "Bye!";
|
||||
message2.poster = poster;
|
||||
poster.messages.add( message2 );
|
||||
session.save( poster );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
Poster posterGotten = (Poster) session.get( Poster.class, poster.pid );
|
||||
assertEquals( 0, posterGotten.pid.intValue() );
|
||||
assertEquals( poster.name, posterGotten.name );
|
||||
assertTrue( Hibernate.isInitialized( posterGotten.messages ) );
|
||||
assertEquals( 2, posterGotten.messages.size() );
|
||||
assertEquals( message1.msgTxt, posterGotten.messages.get( 0 ).msgTxt );
|
||||
assertEquals( message2.msgTxt, posterGotten.messages.get( 1 ).msgTxt );
|
||||
assertSame( posterGotten, posterGotten.messages.get( 0 ).poster );
|
||||
assertSame( posterGotten, posterGotten.messages.get( 1 ).poster );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
{
|
||||
final SingleRootReturnLoadPlanBuilderStrategy strategy = new SingleRootReturnLoadPlanBuilderStrategy(
|
||||
sessionFactory(),
|
||||
LoadQueryInfluencers.NONE
|
||||
);
|
||||
final LoadPlan plan = LoadPlanBuilder.buildRootEntityLoadPlan( strategy, entityPersister );
|
||||
final LoadQueryAliasResolutionContext aliasResolutionContext =
|
||||
new LoadQueryAliasResolutionContextImpl(
|
||||
sessionFactory(),
|
||||
0,
|
||||
Collections.singletonMap( plan.getReturns().get( 0 ), new String[] { "abc" } )
|
||||
);
|
||||
final EntityLoadQueryBuilderImpl queryBuilder = new EntityLoadQueryBuilderImpl(
|
||||
LoadQueryInfluencers.NONE,
|
||||
plan
|
||||
);
|
||||
final String sql = queryBuilder.generateSql( 1, sessionFactory(), aliasResolutionContext );
|
||||
|
||||
final ResultSetProcessorImpl resultSetProcessor = new ResultSetProcessorImpl( plan );
|
||||
final List results = new ArrayList();
|
||||
|
||||
final Session workSession = openSession();
|
||||
workSession.beginTransaction();
|
||||
workSession.doWork(
|
||||
new Work() {
|
||||
@Override
|
||||
public void execute(Connection connection) throws SQLException {
|
||||
PreparedStatement ps = connection.prepareStatement( sql );
|
||||
ps.setInt( 1, 0 );
|
||||
ResultSet resultSet = ps.executeQuery();
|
||||
results.addAll(
|
||||
resultSetProcessor.extractResults(
|
||||
NoOpLoadPlanAdvisor.INSTANCE,
|
||||
resultSet,
|
||||
(SessionImplementor) workSession,
|
||||
new QueryParameters(),
|
||||
new NamedParameterContext() {
|
||||
@Override
|
||||
public int[] getNamedParameterLocations(String name) {
|
||||
return new int[0];
|
||||
}
|
||||
},
|
||||
aliasResolutionContext,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
null
|
||||
)
|
||||
);
|
||||
resultSet.close();
|
||||
ps.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
assertEquals( 2, results.size() );
|
||||
Object result1 = results.get( 0 );
|
||||
assertNotNull( result1 );
|
||||
assertSame( result1, results.get( 1 ) );
|
||||
|
||||
Poster workPoster = ExtraAssertions.assertTyping( Poster.class, result1 );
|
||||
assertEquals( 0, workPoster.pid.intValue() );
|
||||
assertEquals( poster.name, workPoster.name );
|
||||
assertTrue( Hibernate.isInitialized( workPoster.messages ) );
|
||||
assertEquals( 2, workPoster.messages.size() );
|
||||
assertTrue( Hibernate.isInitialized( posterGotten.messages ) );
|
||||
assertEquals( 2, workPoster.messages.size() );
|
||||
assertEquals( message1.msgTxt, workPoster.messages.get( 0 ).msgTxt );
|
||||
assertEquals( message2.msgTxt, workPoster.messages.get( 1 ).msgTxt );
|
||||
assertSame( workPoster, workPoster.messages.get( 0 ).poster );
|
||||
assertSame( workPoster, workPoster.messages.get( 1 ).poster );
|
||||
workSession.getTransaction().commit();
|
||||
workSession.close();
|
||||
}
|
||||
|
||||
// clean up test data
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.delete( poster );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
@Entity( name = "Message" )
|
||||
public static class Message {
|
||||
@Id
|
||||
private Integer mid;
|
||||
private String msgTxt;
|
||||
@ManyToOne
|
||||
@JoinColumn
|
||||
private Poster poster;
|
||||
}
|
||||
|
||||
@Entity( name = "Poster" )
|
||||
public static class Poster {
|
||||
@Id
|
||||
private Integer pid;
|
||||
private String name;
|
||||
@OneToMany(mappedBy = "poster", fetch = FetchType.EAGER, cascade = CascadeType.ALL )
|
||||
private List<Message> messages = new ArrayList<Message>();
|
||||
}
|
||||
}
|
|
@ -70,7 +70,7 @@ import static org.junit.Assert.fail;
|
|||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class EntityWithOneToManyResultSetProcessorTest extends BaseCoreFunctionalTestCase {
|
||||
public class EntityWithNonLazyOneToManySetResultSetProcessorTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
Loading…
Reference in New Issue