Stephen Fikes, there was a question whether or not the forced recreation was necessary in a Map, since it could use a defined key in the query. Here's the issue:
This all boils back down to the @Embeddable having all null property values. Assume for a moment that I don't force the recreation. The way our "Is this collection dirty?" (ie, was a value added, updated, or removed and we need to sync it with the DB) works is comparing all collection values with the DB. As described with HHH-9023, when we query for a component and all properties are returned as null, we return null for the component itself. So when the test case calls #merge and a non-null value is in that collection element, we assume it's new and try to insert it. So, more concisely:
entry == the ContactInfo currently being merged
sn == the Map pulled from the DB ("snapshot")
@Override
@SuppressWarnings("unchecked")
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
final Map sn = (Map) getSnapshot();
final Map.Entry e = (Map.Entry) entry;
return e.getValue() != null && sn.get( e.getKey() ) == null;
}
The last line returns true, since you're trying to merge an instance of ContactInfo (even though all values are null), but the DB snapshot returned null for the component itself (therefore, no entry in the Map). The row insert will be attempted and will fail with a FK constraint exception since it already exists in the DB.
Again, this is working as expected. Conceptually, it normally does not make sense to return a component if all its properties are null, rather than null for the component. We will revisit this under HHH-9023, but it's a new feature.
|