That depends on the "allow lazy loading outside transaction" setting, much like how the outcome of `myEntity.getChildren().size()` depends on same in the proxy solution.
If that is allowed, then the call will build the collection (from a "temporary Session", just like the proxy solution works) and return that. If not allowed, the the call will throw an exception (LazyInitializationException to be precise). I had thought of returning an uninitialized PersistentCollection here, but no matter what you try to do with that collection afterwards will fail. On Thu, Sep 10, 2015 at 2:30 PM Scott Marlow <smar...@redhat.com> wrote: > > > On 09/10/2015 09:45 AM, Steve Ebersole wrote: > > Wanted to get some opinions. I am working on HHH-10055 which is > basically > > a report of problems with that "lazy loading outside of a > > session/transaction" feature when used in combination with bytecode > > enhancement. The initial problem was that bytecode interception was not > > accounting for collection attributes properly; it was not building the > > appropriate PersistentCollection to return. I changed that code to now > > build the PersistentCollection. > > > > But that led to another issue later on that made me question how I was > > building the PersistentCollection during interception. Essentially I was > > trying to still build an uninitialized PersistentCollection. The > > interception code immediately tries to read the size of that collection > as > > and up-front part of its in-line dirty checking capabilities which > > triggered another interception back in to an inconsistent state. > > > > But what I started thinking about is the assumption that this > interception > > ought to prefer to return an uninitialized PersistentCollection. I now > > think that is not a good assumption. Why? Consider code like: > > > > > > Well the idea of an uninitialized PersistentCollection comes from the > > scenario of proxy-based laziness. In proxy-based laziness, code like: > > > > MyEntity myEntity = session.load( MyEntity.class, 1 ); > > System.out.println( myEntity.getName() ); > > > > In the case of proxy-based laziness, the second line immediately causes > the > > entire proxy to become initialized. Part of that is to set any of its > > collection attributes. However, as the collections are not accessed here > > we want to further delay initializing them. But since the proxy is > > initialized completely that means the only way to achieve that here is > > setting an uninitialized version of the PersistentCollection as state, > > which will initialize itself later when accessed. > > > > For bytecode enhancement, the situation is a little bit different. There > > we'd not even build the PersistentCollection instance until that > attribute > > is accessed. So in the above code the collection attributes would never > be > > built. So when we are in the interception code I mentioned above, we > know > > that something is trying to access that collection attribute > specifically. > > This is the difference. > > > > Back to the initial problem... I think the solution is not just to have > the > > bytecode interception code build the PersistentCollection, but to also > have > > it make sure that the PersistentCollection is initialized. > > > > Going back to the sample code, and adding a line: > > > > MyEntity myEntity = session.load( MyEntity.class, 1 ); > > print( myEntity.getName() ); > > myEntity.getChildren(); > > > > In the proxy-based solution the collection is still uninitialized after > > this. For bytecode interception I am proposing that the collection would > > be initialized by that 3rd line. Again we could return the uninitialized > > collection here, and wait for PersistentCollection to initialize itself > on > > first "further access" (calling size(), iterating, etc). I am more think > > through intent; because we know specifically that the collection > attribute > > itself was accessed it seems reasonable to go ahead and initialize it. > > > > And if we do not go that route, then we need a different tact as well for > > dealing with the in-line dirty checking aspect of this. > > > > Really the only time this distinction becomes an issue is in code that > > explicitly tries to check whether certain attributes are initialized. So > > whereas this works for the proxy-based approach: > > > > MyEntity myEntity = session.load( MyEntity.class, 1 ); > > if ( !Hibernate.isInitialized( myEntity.getChildren() ) ) { > > // do something with the uninitialized collection > > ... > > } > > > > It will fail with the bytecode interception approach I propose, because > the > > call to `myEntity.getChildren()` itself causes the initialization. There > > you'd have to use: > > > > MyEntity myEntity = session.load( MyEntity.class, 1 ); > > if ( !Hibernate.isPropertyInitialized( myEntity, "children" ) ) { > > // do something with the uninitialized collection > > ... > > } > > > > which has always been the suggested way to deal with questioning bytecode > > initialization state and which matches the JPA call too. > > > > So any thoughts? > > What happens if the session is closed after the session.load? Will the > collection still be initialized by the time myEntity.getChildren() is > called? > > MyEntity myEntity = session.load( MyEntity.class, 1 ); > session.close(); > print( myEntity.getName() ); > myEntity.getChildren(); > > > > _______________________________________________ > > hibernate-dev mailing list > > hibernate-dev@lists.jboss.org > > https://lists.jboss.org/mailman/listinfo/hibernate-dev > > > _______________________________________________ hibernate-dev mailing list hibernate-dev@lists.jboss.org https://lists.jboss.org/mailman/listinfo/hibernate-dev