-->
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.  [ 2 posts ] 
Author Message
 Post subject: Set property non-updatable from code
PostPosted: Mon May 31, 2010 11:16 am 
Beginner
Beginner

Joined: Tue Nov 27, 2007 1:25 pm
Posts: 24
Hello altogether,

Environment:
nHibernate version: 1.2.1.4000
Repository: M$ SQL Database Server 2005
VS2008, .NET 3.5, C#


Situation:
I'm trying to implement concurrency handling using nHibernate. I have a 'timestamp' column in a database table. As I read that nHibernate and timestamp column from SQL Server 2005 don't get along pretty well, I've implemented a custom IUserVersionType class and used it in my mapping like this:
Code:
<...>
<class name="MyTestProject.DomainModel.BusinessObjects.Document, MyTestProject.DomainModel"
      table="Documents" dynamic-insert="true" dynamic-update="true" lazy="false" optimistic-lock="version">
   <id name="Number" column="DocumentNumber" type="Int64" unsaved-value="0">
      <generator class="identity"/>
   </id>
   <version name="RecordVersion" column="RecordTimestamp" generated="always" unsaved-value="null"
          type="MyTestProject.DomainModel.nHibernate.UserTypes.SqlTimestamp, MyTestProject.DomainModel.nHibernate"/>
<...>


SqlTimestamp implementation:
Code:
   public class SqlTimestamp :
      IUserVersionType
   {
      #region IUserVersionType MEMBERS

      public object Next( object current, ISessionImplementor session )
      {
         return current;
      }

      public object Seed( ISessionImplementor session )
      {
         return new byte[ 8 ];
      }

      #endregion //IUserVersionType MEMBERS

      #region IUserType MEMBERS

      public object Assemble( object cached, object owner )
      {
         return this.DeepCopy( cached );
      }

      public object DeepCopy( object value )
      {
         return value;
      }

      public object Disassemble( object value )
      {
         return this.DeepCopy( value );
      }

      public int GetHashCode( object x )
      {
         return x.GetHashCode();
      }

      public bool IsMutable
      {
         get { return false; }
      }

      public object NullSafeGet( IDataReader rs, string[] names, object owner )
      {
         return rs.GetValue( rs.GetOrdinal( names[ 0 ] ) );
      }

      public void NullSafeSet( IDbCommand cmd, object value, int index )
      {
         NHibernateUtil.Binary.NullSafeSet( cmd, value, index );
      }

      public object Replace( object original, object target, object owner )
      {
         return original;
      }

      public Type ReturnedType
      {
         get { return typeof( byte[] ); }
      }

      public SqlType[] SqlTypes
      {
         get
         {
            SqlType[] types = new SqlType[ 1 ]{ new SqlType( DbType.Binary ) };
            return types;
         }
      }

      #endregion //IUserType MEMBERS

      #region IComparer MEMBERS

      public int Compare( object x, object y )
      {
         byte[] xbytes = (byte[])x;
         byte[] ybytes = (byte[])y;

         if ( xbytes.Length < ybytes.Length )
         {
            return -1;
         }

         if ( xbytes.Length > ybytes.Length )
         {
            return 1;
         }

         for ( int i = 0; i < xbytes.Length; i++ )
         {
            if ( xbytes[ i ] < ybytes[ i ] )
            {
               return -1;
            }
            if ( xbytes[ i ] > ybytes[ i ] )
            {
               return 1;
            }
         }

         return 0;
      }

      bool IUserType.Equals( object x, object y )
      {
         return ( x == y );
      }

      #endregion //IComparer MEMBERS
   }


Problem:
[RecordTimestamp] value is correctly loaded and handled by nHibernate with this implementation, BUT using 'dynamic-insert/update' attribute(s) nHibernate tries to update <version> property every time and thus my operation fails with an error:
System.Data.SqlClient.SqlException: Cannot update a timestamp column.

What I want to accomplish:
Set property [RecordVersion] non-updatable via code.

Acknowledgments:
- override IInterceptor.FindDirty(..) -- IMHO to difficult for this case
- not use 'dynamic-insert/update' attribute(s) -- out of the question

Is there an elegant way in this situation to kindly tell nHibernate to never try to update [RecordTimestamp] value in the database?

Regards,
Mindaugas

P.S. By debugging my audit interceptor (implementation of EmptyInterceptor), I've noticed, that [RecordVersion] property value is the same for current state object and previous state object (setting breakpoint at FindDirty(..) and OnFlushDirty(..)). So why nHibernate includes it into an update statement? And why isn't overridden method Equals(..) or Compare(..) (in SqlTimestamp) get called (to decide is values are the same before including property into "to update" list)?


Top
 Profile  
 
 Post subject: Re: Set property non-updatable from code
PostPosted: Tue Jun 01, 2010 3:18 am 
Beginner
Beginner

Joined: Tue Nov 27, 2007 1:25 pm
Posts: 24
Debugging NHibernate project, NHibernate.Persister.Entity.AbstractEntityPersister:
ScheduledUpdate calls AbstractEntityPersister's method Update(..) on versionable object flush. As my class is marked for 'dynamic-update', Persister retrieves properties to update, thus calling it's GetPropertiesToUpdate(..). This method picks properties that are dirty (=changed) AND (if persisting object is versionable - in my case it is) adds [RecordVersion] property for update, although my versionable property has 'generated=always'... :|

Update: I've noticed, that AbstractEntityPersister's property [PropertyUpdateability] correctly returns properties that can be updated, i.e. [RecordVersion] property is marked as 'non-updatable'. But method GetPropertiesToUpdate(..) ignores that updatable properties collection for versioned property, although checks updatability for dirty properties.. :/


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 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.