Newbie alert! I'm working with existing code, including generated code. It's all Java and XML - no annotations. I'm getting an error about all-delete-orphan an de-referenced collection, but I think this is actually a bug in Hibernate. Based on my debugging, it seems to be the opposite of "you changed the value of the object's collection" - It's actually a case where I believe the collection was created but was never associated with its owner, which looks the same to Hibernate when it becomes time to flush. This is on Hibernate 4.1.0.
In this discussion, there are four entities, A, B1 and B2 (these two are the same type), and C. C is presumed to already exist. A has a foreign key to B1, and both B1 and B2 have a foreign key to C. B1 and B2 also have a child collection, D1 and D2, but these collections have no rows. In the code, A, B1 and B2 are created through SQL statements, and then the objects are "validated" one by one. If a validation error occurs, I just keep track of it and move on to the next one, and report all errors at the end.
The problem occurs when C does not actually exist, and when something in the validation (in my case, it's a validation that occurs in A) tries to access fields through B1 into C (faulting it in to the session). This is a failed validation, and it is all fine when A gets validated, and it's all fine when B1 gets validated. But, when B2 gets validated, C (which doesn't exists) is in some state like it is half-there - the "initialized" flag in the AbstractLazyInitializer says true, so B2 thinks it exists but it causes a IllegalPropertyAccess exception (I think that's what it was), and thus the rest of the setters on the B2 object never get called, including the setter for the collection.
Then, after I've done all my work and I'm flushing my session, I get the standard HibernateException saying Don't dereference this all-delete-orphan collection. But I'm not de-referencing it at all - it just never got set in the first place because the AbstractEntityTuplizer.setPropertyValues() loop exited early because of the problem with the object C.
The code for the AbstractLazyInitializer.initialize() method is below. If I move the
Code:
initialized = true;
to after the
Code:
checkTargetState()
, I don't get the error at flush(). So the question is, does this seem like a real bug to you? Or is it legal for an entity to be "initialized" when it does not exist? Maybe the problem is actually in the AbstractEntityTuplizer, which should maybe catch an exception but keep going to execute all the setters, before throwing one exception at the end? Or do I really need to just stop after the first "object not found" exception?
Code:
public final void initialize() throws HibernateException {
if (!initialized) {
if (session == null) {
throw new LazyInitializationException("could not initialize proxy - no Session");
}
else if (!session.isOpen()) {
throw new LazyInitializationException("could not initialize proxy - the owning Session was closed");
}
else if (!session.isConnected()) {
throw new LazyInitializationException("could not initialize proxy - the owning Session is disconnected");
}
else {
target = session.immediateLoad(entityName, id);
initialized = true;
checkTargetState();
}
}
else {
checkTargetState();
}
}