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