/* * 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.loadplans.process; import javax.persistence.CollectionTable; 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 javax.persistence.JoinColumn; import javax.persistence.ManyToOne; 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.Date; import java.util.List; import org.hibernate.LockMode; import org.hibernate.Session; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.jdbc.Work; import org.hibernate.loader.JoinWalker; import org.hibernate.loader.entity.EntityJoinWalker; import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessor; import org.hibernate.loader.plan.exec.query.spi.NamedParameterContext; import org.hibernate.loader.plan.exec.spi.LoadQueryDetails; import org.hibernate.loader.plan.spi.LoadPlan; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.OuterJoinLoadable; import org.junit.Test; 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, person.address.type.typeName ); // clean up test data session = openSession(); session.beginTransaction(); session.createQuery( "delete Person" ).executeUpdate(); session.getTransaction().commit(); session.close(); } @Test public void testNestedCompositeElementCollectionQueryBuilding() { doCompare( sessionFactory(), (OuterJoinLoadable) sessionFactory().getClassMetadata( Customer.class ) ); } private void doCompare(SessionFactoryImplementor sf, OuterJoinLoadable persister) { final LoadQueryInfluencers influencers = LoadQueryInfluencers.NONE; final LockMode lockMode = LockMode.NONE; final int batchSize = 1; final EntityJoinWalker walker = new EntityJoinWalker( persister, persister.getKeyColumnNames(), batchSize, lockMode, sf, influencers ); final LoadQueryDetails details = Helper.INSTANCE.buildLoadQueryDetails( persister, sf ); compare( walker, details ); } private void compare(JoinWalker walker, LoadQueryDetails details) { System.out.println( "WALKER : " + walker.getSQLString() ); System.out.println( "LOAD-PLAN : " + details.getSqlStatement() ); System.out.println(); } @Test public void testNestedCompositeElementCollectionProcessing() throws Exception { // create some test data Session session = openSession(); session.beginTransaction(); Person person = new Person(); person.id = 1; person.name = "Joe Blow"; session.save( person ); 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 ); investment1.performedBy = person; 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.delete( customerWork.investments.get( 0 ).performedBy ); session.delete( customerWork ); session.getTransaction().commit(); session.close(); } private List<?> getResults(EntityPersister entityPersister ) { final LoadPlan plan = Helper.INSTANCE.buildLoadPlan( sessionFactory(), entityPersister ); final LoadQueryDetails queryDetails = Helper.INSTANCE.buildLoadQueryDetails( plan, sessionFactory() ); final String sql = queryDetails.getSqlStatement(); final ResultSetProcessor resultSetProcessor = queryDetails.getResultSetProcessor(); 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( resultSet, (SessionImplementor) workSession, new QueryParameters(), new NamedParameterContext() { @Override public int[] getNamedParameterLocations(String name) { return new int[0]; } }, 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) @CollectionTable( name = "investments", joinColumns = @JoinColumn( name = "customer_id" ) ) 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; private Person performedBy; @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; } @Column(name="`date`") public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } @ManyToOne public Person getPerformedBy() { return performedBy; } public void setPerformedBy(Person performedBy) { this.performedBy = performedBy; } } @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; } } }