In our previous posts we saw how Hibernate allows the use of eager fetching for collections. We also saw that with more than one collection having eager fetch enabled, how the Cartesian product problem was encountered. But this problem will never occur with Bags. Why? Because bags do not support this feature.
Consider the example of a Basket which has a bag of dry fruits and bag of exotic fruits.
Bags allow duplicates. As we saw earlier, when eager fetching parallel collections a lot of duplicate data is generated. Knowing which of the duplicates are actually valid Bag Entities is difficult. Sub selects or fetch selects need to be used here.
Once one of the joins was removed, the code worked.I removed fetch="join" from dryFruits and the code worked fine.
Consider the example of a Basket which has a bag of dry fruits and bag of exotic fruits.
public class FruitBag { private Integer id; private String color; private Collection<DryFruit> dryFruits = new LinkedList<DryFruit>(); private Collection<ExoticFruit> exoticFruits = new LinkedList<ExoticFruit>(); }The hbm for the same is as below:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.collection.bag.join"> <class name="FruitBag" table="FRUIT_BAG"> <id name="id" type="integer"> <column name="ID" /> <generator class="native" /> </id> <property name="color" type="string"> <column name="COLOR" length="50" not-null="true" /> </property> <bag name="dryFruits" cascade="all-delete-orphan" inverse="true" fetch="join"> <key column="BAG_ID" not-null="true" /> <one-to-many class="DryFruit" /> </bag> <bag name="exoticFruits" cascade="all-delete-orphan" inverse="true" fetch="join"> <key column="BAG_ID" not-null="true" /> <one-to-many class="ExoticFruit" /> </bag> </class> </hibernate-mapping>On trying to load a FruitBag object :
public static void testLoad() { Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); FruitBag basket = (FruitBag) session.load(FruitBag.class, fruitBagId); System.out.println("Number of fruits in " + basket.getColor() + " is " + (basket.getDryFruits().size() + basket.getExoticFruits() .size())); transaction.commit(); session.close(); }On running the code an exception is all we get
Exception in thread "main" org.hibernate.HibernateException: cannot simultaneously fetch multiple bags at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:66) at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:75) at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:43) at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:33) at org.hibernate.loader.entity.BatchingEntityLoader.createBatchingEntityLoader( BatchingEntityLoader.java:103) at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(Ab stractEntityPersister.java:1748) at org.hibernate.persister.entity.AbstractEntityPersister.createEntityLoader(Ab stractEntityPersister.java:1752) at org.hibernate.persister.entity.AbstractEntityPersister.createLoaders(Abstrac tEntityPersister.java:2984) at org.hibernate.persister.entity.AbstractEntityPersister.postInstantiate(Abstr actEntityPersister.java:2977) at org.hibernate.persister.entity.SingleTableEntityPersister.postInstantiate(Si ngleTableEntityPersister.java:690) at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:290) at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294) at com.collection.bag.join.TestJoinBagProblem.main(TestJoinBagProblem.java:16)The reason is simple:
Bags allow duplicates. As we saw earlier, when eager fetching parallel collections a lot of duplicate data is generated. Knowing which of the duplicates are actually valid Bag Entities is difficult. Sub selects or fetch selects need to be used here.
Once one of the joins was removed, the code worked.I removed fetch="join" from dryFruits and the code worked fine.
/* load com.collection.bag.join.FruitBag */ select fruitbag0_.ID as ID0_1_, fruitbag0_.COLOR as COLOR0_1_, exoticfrui1_.BAG_ID as BAG3_3_, exoticfrui1_.ID as ID3_, exoticfrui1_.ID as ID2_0_, exoticfrui1_.Name as Name2_0_, exoticfrui1_.bag_id as bag3_2_0_ from FRUIT_BAG fruitbag0_ left outer join EXOTIC_FRUIT exoticfrui1_ on fruitbag0_.ID=exoticfrui1_.BAG_ID where fruitbag0_.ID= ? /* load one-to-many com.collection.bag.join.FruitBag.dryFruits */ select dryfruits0_.BAG_ID as BAG3_1_, dryfruits0_.ID as ID1_, dryfruits0_.ID as ID1_0_, dryfruits0_.Name as Name1_0_, dryfruits0_.bag_id as bag3_1_0_ from DRY_FRUIT dryfruits0_ where dryfruits0_.BAG_ID= ?It is when we have more than one bag with join fetch, that the code fails. It in fact fails at start up itself. Hibernate doesn't even attempt to generate the queries.
Waths solutions
ReplyDelete