-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 
Author Message
 Post subject: URGENT: StaleObjectStateException when there shouldn't be
PostPosted: Mon Dec 26, 2005 8:27 pm 
Regular
Regular

Joined: Thu May 12, 2005 10:12 am
Posts: 71
Location: Buenos Aires, Argentina
Hi, I've been tracking a strange problem all day and I'm not sure where to start to go from now. I'm using the latest NH 1.0.1 with a SQL 2000. The problem is strange because sometimes under the very same circumstances the bug does not show up. I'll try to explain as much as I can.

The bug appears in an async process. This process is asigned the lowest thread priority. The process reads some files and creates entites as it goes along. The process goes on adding entites (PlazoFijo) to a Bag. At some point it finishes and sees that there was an error so it issues (before commiting the transaction) a .Clear() on the collection. Then I get then following exception:

2005-12-26 21:04:14,760 [320] ERROR - An operation failed due to stale data
NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction for SAFJP.SICI.Model.Carteras.Custodias.PlazoFijo instance with identifier: -1

I debug the code to NH up to where it issues a delete for the entity with an ID= -1 and does a Check(). This strikes me as odd, why did NH marked this particular entity for delete with a SQL statement since I have set the unsaved-value = -1 on the Id. Also, how is it possible that some entities in the bag have an Id != -1 and the last dont.

Worst is that some times under the same circimstances the bug does not appear. I'm suspecting the Cache could be involved but not sure how.

Thanks for any help, I'm kinda desperate at this point

Following are the HBMs. Sorry its in spanish (client request :( ). The bug appears to be after adding PlazoFijo to UploadCustodia. UploadCustodia is a hierarchy mapped with table-per-hierarchy and PlazoFijo is mapped as a table-per-class.

Note: I've debugged NH a couple of times, so any help on where to look at the source code. Maybe it is a bug after all....

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
   xmlns="urn:nhibernate-mapping-2.0" 
   namespace="SAFJP.SICI.Model.Common.Uploads"
   assembly="SAFJP.SICI.Model.Common"
   default-access="field">
   
   <class
      name="Upload"
      table="T_Upload"
      proxy="Upload">
      
      <id
         name="mId"
         column="upload_ID"
         type="Int32"
         unsaved-value="-1">
         <generator class="native"/>
      </id>
      
      <discriminator
         column="tipoUpload_Class"
         type="String"
         length="15"
      />
      
      <property
         name="mFechaUpload"
         column="D_upload"
         type="DateTime"
      />
      
      <property
         name="mFechaDatos"
         column="D_datos"
         type="DateTime"
      />
      
      <many-to-one 
         name="mEstado"
         column="estadoUpload_ID"
         class="SAFJP.SICI.Model.Common.Uploads.EstadosUploads.EstadoUpload"
      />
            
      <many-to-one 
         name="mUsuario"
         column="usuarioSICI_ID"
         class="SAFJP.SICI.Security.UsuarioSICI, SAFJP.SICI.Security"
      />
      
      <bag
         name="mErrores"
         order-by="error_ID"
         cascade="all-delete-orphan"
         lazy="true">
         <key column="upload_ID" />
         <one-to-many class="ErrorUpload" />
      </bag>
      
      <!-- ==========================   -->
      <!-- Subclase UploadAFIP      -->
      <!-- ==========================   -->
      <subclass
         name="SAFJP.SICI.Model.Carteras.AFIP.UploadAFIP,SAFJP.SICI.Model.Carteras"
         proxy="SAFJP.SICI.Model.Carteras.AFIP.UploadAFIP,SAFJP.SICI.Model.Carteras"
         discriminator-value="UP_AFIP">
            
         <bag
            name="mRecaudaciones"
            cascade="all-delete-orphan"
            lazy="true">
            
            <key column="uploadAFIP_ID" />
            
            <one-to-many class="SAFJP.SICI.Model.Carteras.AFIP.RecaudacionAFJP,SAFJP.SICI.Model.Carteras"/>
            
         </bag>
      
      </subclass>
      

      <!-- ==========================   -->
      <!-- Subclase UploadCotizacion   -->
      <!-- ==========================   -->
      <subclass
         name="SAFJP.SICI.Model.Carteras.Cotizaciones.UploadCotizacion,SAFJP.SICI.Model.Carteras"
         proxy="SAFJP.SICI.Model.Carteras.Cotizaciones.UploadCotizacion,SAFJP.SICI.Model.Carteras"
         discriminator-value="UP_COTIZACION">
         
         <bag
            name="mCotizaciones"
            cascade="all-delete-orphan"
            lazy="true">
            <key column="uploadCotizacion_ID" />
            <one-to-many class="SAFJP.SICI.Model.RecursosFinancieros.Cotizaciones.Cotizacion,SAFJP.SICI.Model.RecursosFinancieros"/>
         </bag>
      
      
      </subclass>
      
      <!-- ==========================   -->
      <!-- Subclase UploadCustodia   -->
      <!-- ==========================   -->
      <subclass
         name="SAFJP.SICI.Model.Carteras.Custodias.UploadCustodia,SAFJP.SICI.Model.Carteras"
         proxy="SAFJP.SICI.Model.Carteras.Custodias.UploadCustodia,SAFJP.SICI.Model.Carteras"
         discriminator-value="UP_CUSTODIA">
         
         <many-to-one
            name="mCustodia"
            column="custodia_ID"
            class="SAFJP.SICI.Model.RecursosFinancieros.Custodia, SAFJP.SICI.Model.RecursosFinancieros"
         />
         
         <bag
            name="mPlazosFijos"
            order-by="elementoCustodiado_ID"
            cascade="all-delete-orphan"
            lazy="true"
            inverse="true">
            <key column="uploadCustodia_ID" />
            <one-to-many class="SAFJP.SICI.Model.Carteras.Custodias.PlazoFijo,SAFJP.SICI.Model.Carteras"/>
         </bag>

         <bag
            name="mInversiones"
            order-by="elementoCustodiado_ID"
            cascade="all-delete-orphan"
            lazy="true">
            <key column="uploadCustodia_ID" />
            <one-to-many class="SAFJP.SICI.Model.Carteras.Custodias.Inversion,SAFJP.SICI.Model.Carteras"/>
         </bag>
         
         <bag
            name="mCuentasCorrientes"
            order-by="elementoCustodiado_ID"
            cascade="all-delete-orphan"
            lazy="true">
            <key column="uploadCustodia_ID" />
            <one-to-many class="SAFJP.SICI.Model.Carteras.Custodias.CuentaCorrienteCustodia,SAFJP.SICI.Model.Carteras"/>
         </bag>
      
      </subclass>
   </class>
</hibernate-mapping>



Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
   xmlns="urn:nhibernate-mapping-2.0"
   namespace="SAFJP.SICI.Model.Carteras.Custodias"
   assembly="SAFJP.SICI.Model.Carteras"
   default-access="field">
   
   <class
      name="ElementoCustodiado"
      table="T_Elemento_Custodiado">
      
      <id
         name="mId"
         column="elementoCustodiado_ID"
         type="Int32"
         unsaved-value="-1">
         <generator class="native" />
      </id>
      
      <property
         name="mCodigoAFJP"
         column="codigoAfjp"
         type="String"
         length="4"
      />
      
      <many-to-one
         name="mAfjp"
         column="AFJP_ID"
         class="SAFJP.SICI.Model.RecursosFinancieros.AFJP,SAFJP.SICI.Model.RecursosFinancieros"
      />
      
      <!-- ================================  -->
      <!-- Subclass PlazoFijo               -->
      <!-- ================================  -->
      <joined-subclass
         name="PlazoFijo"
         table="T_Plazo_Fijo">
         
         <key column="elementoCustodiado_ID" />
         
         <property
            name="mCodigoBanco"
            column="codigoBanco"
            type="Int32"
         />
            
         <property
            name="mTipoDeposito"
            column="tipoDeposito"
            type="String"
         />
         
         <property
            name="mNumeroDeposito"
            column="N_deposito"
            type="String"
         />
         
         <property
            name="mFechaEmision"
            column="D_emision"
            type="DateTime"
         />
         
         <property
            name="mFechaVencimiento"
            column="D_vencimiento"
            type="DateTime"
         />
         
         <property
            name="mMontoInicial"
            type="SAFJP.SICI.Model.NHUserTypes.DineroUserType, SAFJP.SICI.Model.NHUserTypes">
            <column name="A_montoInicial" />
            <column name="codigoMonedaMontoInicial_ID" />
         </property>
         
         <many-to-one
            name="mTipoCartera"
            class="SAFJP.SICI.Model.Carteras.TipoCartera"
            column="codigoCartera"
         />
                        
         <many-to-one
            name="mUpload"
            column="uploadCustodia_ID"
            class="SAFJP.SICI.Model.Carteras.Custodias.UploadCustodia"
         />   
      
      </joined-subclass>
      
      
      <!-- ================================  -->
      <!-- Subclass Inversion               -->
      <!-- ================================  -->
      <joined-subclass
         name="Inversion"
         table="T_Inversion">
         
         <key column="elementoCustodiado_ID" />
         
         <property
            name="mCodigoCarteraInformado"
            column="codigoCarteraInformado"
            type="string"
            length="2"
         />
         
         <many-to-one
            name="mTipoCartera"
            class="SAFJP.SICI.Model.Carteras.TipoCartera"
            column="codigoCartera"
         />
         
         <property
            name="mCodigoSAFJP"
            column="codigoSAFJP"
            type="String"
            length="20"
         />
         
         <property
            name="mCodigoISIN"
            column="codigoISIN"
            type="String"
            length="20"
         />
         
         <property
            name="mCantidadNominal"
            column="Q_nominal"
            type="Decimal"
         />
         
         <many-to-one
            name="mUpload"
            column="uploadCustodia_ID"
            class="SAFJP.SICI.Model.Carteras.Custodias.UploadCustodia"
         />
         
      </joined-subclass>
      
      
      <!-- ================================  -->
      <!-- Subclass Inversion               -->
      <!-- ================================  -->
      <joined-subclass
         name="CuentaCorrienteCustodia"
         table="T_Cuenta_Corriente_Custodia">
         
         <key column="elementoCustodiado_ID" />
         
         <property
            name="mCodigoBanco"
            column="codigoBanco"
            type="Int32"
         />
                  
         <property
            name="mTipoGeneralCartera"
            column="tipoGeneralCartera"
         />
         
         <property
            name="mNumeroCuenta"
            column="N_cuenta"
            type="String"
         />
         
         <property
            name="mSaldo"
            type="SAFJP.SICI.Model.NHUserTypes.DineroUserType, SAFJP.SICI.Model.NHUserTypes">
            <column name="A_saldo" />
            <column name="codigoMonedaSaldo_ID" />
         </property>
         
         <many-to-one
            name="mUpload"
            column="uploadCustodia_ID"
            class="SAFJP.SICI.Model.Carteras.Custodias.UploadCustodia"
         />
         
      </joined-subclass>
      
   </class>
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 27, 2005 6:57 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
I think you somehow managed to call Save on an object with id -1 (Save doesn't check unsaved-value, only SaveOrUpdate does), and you also stored it in the bag. Or maybe you managed to Load the object with id -1. It's hard to tell...


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 27, 2005 8:22 am 
Regular
Regular

Joined: Thu May 12, 2005 10:12 am
Posts: 71
Location: Buenos Aires, Argentina
I never actually called Save on the object directly. The objects in the bag gets persisted because of cascading. I'll try to set a brakepoint in the load to see if it stops there.

any other ideas?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 27, 2005 10:10 am 
Regular
Regular

Joined: Fri Jun 11, 2004 6:27 am
Posts: 81
Location: Yaroslavl, Russia
Maybe you have interceptor and its IsUnsaved returned false for your object? In this case unsaved-value attribute isn't used.

_________________
Best,
Andrew Mayorov // BYTE-force


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 27, 2005 1:30 pm 
Regular
Regular

Joined: Thu May 12, 2005 10:12 am
Posts: 71
Location: Buenos Aires, Argentina
I've checked and I'm not using any interceptor.

Here's what I found so far. After processing a file line I create the entity and add it to the collection making sure the both directions are set. While the next line is processed i need to execute a HQL query that forces NH to flush what it has in memory. At this point the saved entity gets a new valid ID.

The problem is that the last entity added never gets flushed so its id remains -1. At a later time, when the application throws (and catches) and exception the collection are cleared and the reference set to null. Then hibernate tries to delete all of the entities with a DELETE statement, which is correct EXCEPT for the last entity that was never actually flushed so a DELETE is not needed. The entity was always transient.

Please I need someone to help on this. I have a deployment on Friday and loosing my hairs pretty fast :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 27, 2005 2:36 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
roniburd wrote:
At a later time, when the application throws (and catches) and exception the collection are cleared and the reference set to null. Then hibernate tries to delete all of the entities with a DELETE statement, which is correct EXCEPT for the last entity that was never actually flushed so a DELETE is not needed. The entity was always transient.


1. Why was it always transient? If it was part of a collection, it should have been saved during the Flush. Why does it never get flushed?

2. Are you reusing a session after a HibernateException?

I think we have guessed enough, now you will have to show us your code :) Or try building a simple test case and if the problem is still present in the simple test, report it.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 27, 2005 2:45 pm 
Regular
Regular

Joined: Thu May 12, 2005 10:12 am
Posts: 71
Location: Buenos Aires, Argentina
Fair enough...I'll try to build a test code. I'm not sure how to do UnitTest with 2 thread fired in an async manner but can try my best.

Regarding the exception: no. I'm not re-using the session. I'm traping the exception and changing the object accordingly. The session never "sees" the exception.

Thanks for all the help so far!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 27, 2005 5:25 pm 
Regular
Regular

Joined: Thu May 12, 2005 10:12 am
Posts: 71
Location: Buenos Aires, Argentina
I found a hack that works. Basicaly is doing forcing a Flush before clearing the collection. I'll do my best to try and replicate this problem in a unit test.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.