Attribute converters and dirty checks
by Gunnar Morling
Hi,
I have an entity with an attribute whose value is converted by means
of an attribute converter. The converter operations are not symmetric,
i.e. it's not guaranteed that
value.equals( convertToEntityAttribute( convertToDatabaseColumn( value ) ) )
is true.
Question 1: Is such converter valid, or is it a requirement that its
operations are symmetric?
If this converter is valid, then I am curious whether the following
optimization could be applied.
Currently, the dirty checking is based on equality comparison of the
attribute value. During persist a deep copy of the entity attribute
array is made, which does the forth-and-back conversion above. If the
converter isn't symmetric, this may yield a value which is different
from the one in the entity attribute.
Then at dirty check, the entity attribute is compared to that value
resulting from deep-copying, causing the property to be considered
dirty, although the value to be stored in the database actually is the
same. Subsequently, an UPDATE will be issued which contains the same
column value as the previous INSERT.
So, question 2: Would it be feasible to do the dirty check based on
the converted value?
Thanks,
--Gunnar
8 years, 10 months
Quoting JPA specs
by Vlad Mihalcea
Hi,
I know that any quoting from a copyrighted material needs written approval.
The JPA specs are under copyright, so instead of quoting we should just
provide the section and
make a summary in our own wording.
Vlad
8 years, 10 months
Hibernate forum inactive users pruning
by Vlad Mihalcea
Hi,
Among all 75000 registered users, 10000 used to be inactive ones
(registered without any post).
Regular users are always creating an account and post at least one question
on the forum, so there is no reason why we should keep 13 years old user
accounts that haven't posted anything on the forum.
Most have been registered with temporary email addresses or other spam
domain names.
I deleted those and now the forum is so much faster.
Vlad
8 years, 10 months
HHH-5855 bug report and a possible fix
by Vlad Mihalcea
Hi guys
I decided to spend some time to investigate the infamous HHH-5855 (
https://hibernate.atlassian.net/browse/HHH-5855 ) bug and this is my
report.
One of the first thing that I noticed is that Sets are fine, while this bug
only replicates with bidirectional Bags.
After some hours of debugging and logging (since debugging triggers
collection initialization), I found the culprit.
In the org.hibernate.type.TypeHelper.replace(Object[] original, Object[]
target, Type[] types, SessionImplementor session, Object owner, Map
copyCache) method, when copying the cached entity state (which contains the
newly added child entity along with its identifier) onto the original
collection:
copied[i] = types[i].replace( original[i], target[i], session, owner,
copyCache );
inside the org.hibernate.type.CollectionType.replace(Object[] original,
Object[] target, Type[] types, SessionImplementor session, Object owner,
Map copyCache) method there is this check:
if ( !Hibernate.isInitialized( original ) ) {
return target;
}
For Sets, the collection is always initialized because of this line inside
the add() method of the org.hibernate.collection.internal.PersistentSet:
final Boolean exists = isOperationQueueEnabled() ?
readElementExistence( value ) : null;
Because of the the readElementExistence( value ) call the Set is always
initialized and upon triggering the flush, the newly added Entity being
already managed it will be left alone.
For PersistentList the aforementioned check is false and the replace never
occurs, hence the transient entity lingers in the persistence context and
the flush will trigger another insert, so we get duplicates.
To make the Bag behave like the Set, all we need to do is to change the add
method like this:
public boolean add(Object object) {
initialize(false);
if ( !isOperationQueueEnabled() ) {
write();
return bag.add( object );
}
else {
queueOperation( new SimpleAdd( object ) );
return true;
}
}
but then four tests will fail:
org.hibernate.test.legacy.MasterDetailTest > testQueuedBagAdds FAILED
java.lang.AssertionError at MasterDetailTest.java:1068
org.hibernate.test.unionsubclass.UnionSubclassTest > testUnionSubclass
FAILED
org.hibernate.ObjectDeletedException at UnionSubclassTest.java:364
org.hibernate.test.version.VersionTest > testCollectionNoVersion FAILED
java.lang.AssertionError at VersionTest.java:118
org.hibernate.test.version.VersionTest > testCollectionVersion FAILED
java.lang.AssertionError at VersionTest.java:79
3 of them fail because we expect the List not to be initialized and
the UnionSubclassTest fails
for a doubtful reason (we attempt to delete an entity which is still
referenced).
Basically, such a change will finally fix this issue and the Sets and Lists
will behave consistently. Since you know the reasons behind the difference
in how Sets and Lists are initialized, we need to discuss if this change is
appropriate or we should address this issue differently.
I have a branch on my fork with a test that replicates this issue and that
the proposed change manages to fix it:
https://github.com/vladmihalcea/hibernate-orm/tree/feature/hhh5855
Let me know what you think and let's discuss it further.
Vlad
8 years, 10 months
[OGM] @Column and embedded objects in OGM
by Emmanuel Bernard
Hey guys,
Marco found something that really surprised him. I am not sure if that’s a widespread behavior or just specific to CouchDB’s backend.
@Entity
class A {
…
B embedded;
}
@Embeddable
class B {
String c;
@Column(name=“real_d”) d;
}
The document structure is roughly
{
…
“embedded”: { “c”: “foo” },
“real_d”: “bar"
}
I can see this is happening because the column name has not dot in it. But I would expect as a noob to see the natural behavior and have real_d embedded in the nested document embedded.
Looks like MongoDB does the same and I suspect Noe4J too.
1. Can any one think of a trick (like the naming strategy or something like that) to compensate and do it “right”.
2. If not, I could not find anything in the documentation nor the FAQ and we should make that very obvious. I finally found some info in the embedded section of MongoDB but Neo4J and CouchDb are silent on the matter. How could we make that clearer in the mean time? FAQ?
Emmanuel
8 years, 10 months