A have a trouble with Hibernate.
In a nutshell: I fetch an instance of class with natural-id from database. I do session.setReadOnly(thatInstance, true). After that I fetch something else from DB, which results in org.hibernate.HibernateException: immutable natural identifier of an instance of <ThatClass> was altered. If I remove setReadOnly() it works just fine.
I have a class with natural identifier mapped as:
Code:
<class name="Attribute" discriminator-value="0">
<id name="id" type="integer">
<generator class="seqhilo">
<param name="sequence">ATTRIBUTE_SEQ</param>
<param name="max_lo">10</param>
</generator>
</id>
<discriminator type="integer" column="TYPE_ID" />
<natural-id>
<many-to-one name="section"
not-null="true"
class="GoodsSection"
column="SECTION_ID"
insert="false" update="false" />
<property name="outerId" not-null="true" />
</natural-id>
<subclass name="ru.sbtc.shop.value_object.attribute.IntAttribute" discriminator-value="1" />
...
<subclass name="ru.sbtc.shop.value_object.attribute.URLAttribute" discriminator-value="11" />
</class>
I do
Code:
Attribute attr = Attribute.findBySectionAndOuterId(GoodsSection.root(), "image", false);
session.setReadOnly(attr, true);
AttributeType.getAll();
And I get an exception:
Code:
org.hibernate.HibernateException: immutable natural identifier of an instance
of ru.sbtc.shop.value_object.attribute.ImageFileAttribute was altered
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkNaturalId(DefaultFlushEntityEventListener.java:94)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:169)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:120)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:35)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:969)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1114)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
at ru.sbtc.shop.value_object.AttributeType.getAll(AttributeType.java:95)
AttributeType is a rather boring class which have no direct references on Attribute and vice versa.
I do not want this exception to happen since I don't modify that Attribute.
And I don't understand why hibernate checks that if I've declated that instance as read-only - isn't it supposted to NOT ditry-check and NOT try to persist it?
P.S. Maybe I'm doing the wrong thing.
What I need is preview mode: I.e. I make some changes to object, getAsXML() it to build preview changes page, but surely don't want to persist it because that's a preview only. I haven't found the right way to do that how would you do that?
P.P.S. I've found this:
[url=http://lists.jboss.org/pipermail/hibernate-issues/2006-November.txt.gz]> i just upgraded from 3.0.5 to 3.1.2, and i started seeing this problem. i'm not exactly sure where the bug is here, but this is what i'm seeing:
> i have a class, Subscription, which has a natural-id of class Subscriber and Edition (excerpts of relevant mapping files below).
> when Subscription is unloaded, if i make a change, then commit the session, i see this exception:
> HibernateException: immutable natural identifier of an instance of Subscription was altered
> this gets thrown from DefaultFlushEntityEventListener.checkNaturalId() line 80.
> i traced through that method, this is what happens:
> 1. in checkNaturalId, loaded == null , so getNaturalIdSnapshot() is called
> 2. this ends up generating some sql that selects the SubscriptionId and EditionId from the Subscription row.
> 3. the sql is generated in AbstractEntityPersister.getNaturalIdentifierSnapshot(), which calls hydrate for each returned column of the natural-id,
> 4. but hydrate only returns the id, instead of the actual entity
> 5. so this array of ids (instead of entities) ends up back in DefaultFlushEntityEventListener.checkNaturalId() as 'loaded', which gets compared to 'current'
> the trouble is that 'current' contains the entities, but 'loaded' only contains the ids of those entites, so the natural-id check fails, and i get the exception.
> this only happens when 'loaded' is null in checkNaturalId().
> the javadocs for hydrate say you have to call "resolve" afterwards... this isn't being done, so maybe thats the fix. if the natural-id is not just simple properties, then resolve should also be called.[/url]
Did I stumble on that bug? Are there any fixes? I use Hibernate 3.2.5 ga.