Weird Behavior of Cache with fetchmode join and scroll-iterator

Description

Hi guys,

i found out a weird behavior with the collectionsCache when I overwrite the Fetchmode in a Criteria-query to JoinMode and use the scroll-iterator. It seems like the query builds every single child as a bag and puts it into the second-level-collection-cache.
It seems not to act like an O/R-Mapper. Such Join-Statements should be grouped or at least not corrupt the cache.
Background: I want to preheat the Secondlevel-cache with just one statement. i get rid of the ripple loading.

example

City.java:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class City { @Id @GeneratedValue private Long id; private String name; @OneToMany(fetch = FetchType.LAZY, mappedBy = "city") @Cache(usage=CacheConcurrencyStrategy.READ_WRITE) private List<Citizen> citizens = new ArrayList<Citizen>(); public City(String name) { this.name = name; } public City() { } public List<Citizen> getCitizens() { return citizens; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

Citizen.java:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.*; @Entity @Cacheable @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class Citizen { @Id @GeneratedValue private Long id; private String name; @ManyToOne private City city; public Citizen(String name) { this.name = name; } public Citizen() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public City getCity() { return city; } public void setCity(City city) { this.city = city; } }

the TestCase:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 import junit.framework.Assert; import org.hibernate.*; import org.hibernate.cfg.Configuration; import org.hibernate.criterion.Restrictions; import org.junit.Before; import java.util.List; public class FetchModeTest { private SessionFactory factory; @Before public void setUp() throws Exception { // just create 2 cities with 2 citizens in both cities factory = new Configuration().configure( "hibernate.cfg.xml").addAnnotatedClass(Citizen.class).addAnnotatedClass(City.class) .buildSessionFactory(); Session session = factory.openSession(); City berlin = new City("Berlin"); session.save(berlin); Citizen hans = new Citizen("Hans"); hans.setCity(berlin); session.save(hans); berlin.getCitizens().add(hans); Citizen peter = new Citizen("Peter"); peter.setCity(berlin); session.save(peter); berlin.getCitizens().add(peter); session.save(berlin); session.flush(); City hamburg = new City("Hamburg"); session.save(hamburg); Citizen horst = new Citizen("Horst"); horst.setCity(hamburg); session.save(horst); Citizen anne = new Citizen("Anne"); anne.setCity(hamburg); session.save(anne); hamburg.getCitizens().add(horst); hamburg.getCitizens().add(anne); session.close(); factory.getCache().evictEntityRegions(); //clear 2-level-cache factory.getCache().evictCollectionRegions(); //clear 2-level-cache collections } @org.junit.Test //PASSED!!! public void testWithJoinAndList() throws Exception { preHeatCacheWithJoinAndList(); Session newSession = factory.openSession(); City berlin = (City) newSession.createCriteria(City.class).add(Restrictions.eq("name", "Berlin")).uniqueResult(); Assert.assertEquals(2, berlin.getCitizens().size()); newSession.close(); } @org.junit.Test //FAILED!!! public void testWithJoinAndScroll() throws Exception { preheatCacheWithJoinAndScroll(); Session newSession = factory.openSession(); City berlin = (City) newSession.createCriteria(City.class).add(Restrictions.eq("name", "Berlin")).uniqueResult(); Assert.assertEquals(2, berlin.getCitizens().size()); newSession.close(); } private void preHeatCacheWithJoinAndList() { Session preheatSession = factory.openSession(); List<City> list = preheatSession.createCriteria(City.class).setFetchMode("citizens", FetchMode.JOIN).list(); for (City city : list) { Hibernate.initialize(city); //citizen-bag has 2 Element } preheatSession.close(); } private void preheatCacheWithJoinAndScroll() { Session preheatSession = factory.openSession(); ScrollableResults cursor = preheatSession.createCriteria(City.class).setFetchMode("citizens", FetchMode.JOIN).scroll(); while (cursor.next()) { City city = (City) cursor.get(0); Hibernate.initialize(city); //citizen-bag has just 1 Element } preheatSession.close(); } }

thanks

Environment

org.hibernate.dialect.H2Dialect, In-Memory-DB

Status

Assignee

Unassigned

Reporter

Karolis Kleiza

Fix versions

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

4.3.10
5.0.2
4.3.9

Priority

Critical
Configure