-->
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.  [ 11 posts ] 
Author Message
 Post subject: Version-tag in joined-subclass
PostPosted: Thu Apr 03, 2008 9:47 am 
Newbie

Joined: Thu Apr 03, 2008 7:40 am
Posts: 4
Location: Ghent, Belgium
Database: Microsoft SQL Server 2000
Hibernate version: NHibernate 1.2.0
Hibernate mapping version: 2.2
.NET version: 2.0
Visual studio version: 2005


Hi all,

(First you will see the description of our situation, my question is formulated at the end of the post)

We use versioning for optimistic locking (MSSQL timestamp column) in each table in the database that contains editable data. In the NHibernate mapping the version-tag is used to support the versioning. This feature works excellent in NHibernate as such.

Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" namespace="..."  assembly="...">
   <class name="..." table="..." lazy="true" optimistic-lock="version">
      ...
      <version name="_Version" column="Version" type="..." generated="always" unsaved-value="null" />
      ...
   </class>
</hibernate-mapping>



We are also using Inheritance Mapping to map our contact-mechanism in our database (contact-mechanism = entity that represents a way to contact a person). This feature works fine as such.

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" namespace="..." assembly="...">
   <class name="ContactMechanism" table="ContactMechanism" lazy="true" optimistic-lock="version">

      <id name="_ContactMechanismId" column="ContactMechanismId" type="..." unsaved-value="...">
         <generator class="..."/>
      </id>

      <version name="_Version" column="Version" type="..." generated="always" unsaved-value="null" />
      <property column="Comment" type="String" name="_Comment" length="200" />

   </class>
</hibernate-mapping>



Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" namespace="..." assembly="...">
   <joined-subclass name="Address" table="Address" lazy="true" extends="ContactMechanism">
      <key column="ContactMechanismId" />
      ...
   </joined-subclass>
</hibernate-mapping>





Unfortunately versioning can only be mapped inside a class-tag of the Hibernate 2.2 schema, and not in the joined-subclass-tag.
This means in case of our contact-mechanism that only the base-class (and base-table) can contain a version field, and that all derived classes (and tables) can not.

Nevertheless both base and derived classes need a version field because they both contain editable data and each of them could be edited separately from outside the application scope.


Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" namespace="..." assembly="...">
   <joined-subclass name="Address" table="Address" lazy="true" extends="ContactMechanism">
      <key column="ContactMechanismId" />

      <!-- version-tag is not allowed here -->

      ...

   </joined-subclass>
</hibernate-mapping>



To complete the description of our situation, here is the database schema of the contact-mechanism:

Image

and the class diagram of the contact-mechanism:

Image


Now here is my question:
Is there is no need for a version-tag in the joined-subclass-tag? In other words: Is my database structure wrong?

- OR -

Is this a limitation of (N)Hibernate? In other words: Can this particular case not be handled by (N)Hibernate?
Will it purhaps in the future???



Any help on this topic will be very much appreciated and thank you for reading my post.



ds38
Ghent
Belgium


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 10:18 am 
Beginner
Beginner

Joined: Fri Aug 10, 2007 3:34 am
Posts: 44
Quote:
Nevertheless both base and derived classes need a version field because they both contain editable data and each of them could be edited separately from outside the application scope.

Usually when u edit the child object it's version is changed in the parent table, so it's not necessary to have the version column in the child table.

on the other hand, if you edit it (the version) outside the application scope you might have problems...


Top
 Profile  
 
 Post subject: RE: Matrasinator
PostPosted: Thu Apr 03, 2008 10:37 am 
Newbie

Joined: Thu Apr 03, 2008 7:40 am
Posts: 4
Location: Ghent, Belgium
Hi Matrasinator,


Thanks for your reply.

You are completely right when you assume that NHibernate is the only "Data Layer" the database will have.

But because this project will become a major enterprise application (with DBAs who will probably access the DB directly, small custom tools using ADO.NET, migration tools, stored procedures that edit more than one table, ... as so often occurs) I must assume that every table inside the database can be edited outside the application scope of NHibernate.

It's common sense as well: Why check only one table, when you can check them both (just to be safe)?


Kind regards,

ds38


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 03, 2008 12:14 pm 
Regular
Regular

Joined: Mon Mar 20, 2006 10:49 pm
Posts: 59
NHibernate's perspective is that the rows in the joined-subclass are logically associated with the corresponding rows in the superclass table and therefore there is no need for more than one version column. Put another way, NHibernate is versioning class instances, not table rows.

IMO, the cleanest way to meet your requirements would be to put an update trigger on the joined-subclass table which does nothing but poke the corresponding row(s) in the superclass table to force the timestamp to be updated.

_________________
Mike Abraham


Top
 Profile  
 
 Post subject: RE: mabraham
PostPosted: Fri Apr 04, 2008 3:52 am 
Newbie

Joined: Thu Apr 03, 2008 7:40 am
Posts: 4
Location: Ghent, Belgium
Hi mabraham,


Thank you for your reply.

First and for all, I don't agree with your statement that "NHibernate is versioning class instances, not table rows".
I.m.o. versioning is exclusive for tables (version is also called RowVersion in some communities). Class instances are or should be managed in memory by the Session or any other custom class. Futhermore I believe any O/R Mapper should serve the existing DB structure and not the other way around.

On your second remark:
The problem is not that the version-timestamp doesn't get updated. The problem is that NHibernate is not checking it when making updates of it's own.
The Timestamp type in MSSQL 2000 is native and the value is always updated automatically, as you can see in my code sample:

Code:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="true" namespace="..."  assembly="...">
   <class name="..." table="..." lazy="true" optimistic-lock="version">
      ...
      <version ... generated="always" ... />
      ...
   </class>
</hibernate-mapping>




Nevertheless you have given me something to reflect about. I do see your point, but in my mind the inheritance mapping is not watertight. Whatever the perspective of in NHibernate may be, it remains possible to make changes in the DB without NHibernate knowing about it.



Kind regards,

ds38


Top
 Profile  
 
 Post subject: Re: Version-tag in joined-subclass
PostPosted: Tue Jun 10, 2008 1:06 pm 
Newbie

Joined: Tue Jun 10, 2008 12:59 pm
Posts: 1
ds38 wrote:
Database: Microsoft SQL Server 2000
Hibernate version: NHibernate 1.2.0
Hibernate mapping version: 2.2
.NET version: 2.0
Visual studio version: 2005

Hi all,
(First you will see the description of our situation, my question is formulated at the end of the post)

We use versioning for optimistic locking (MSSQL timestamp column) in each table in the database that contains editable data. In the NHibernate mapping the version-tag is used to support the versioning. This feature works excellent in NHibernate as such.



I'm interested in this statement, as my understanding is that NHibernate does not support MSSqlServer TimeStamp columns for row version control. Did you really mean that you're using MSSql DataType TimeStamp (database-controlled version column)? What type value do you give NH?


Top
 Profile  
 
 Post subject: MS SQL Server Timestamp type
PostPosted: Wed Jun 11, 2008 4:15 am 
Newbie

Joined: Thu Apr 03, 2008 7:40 am
Posts: 4
Location: Ghent, Belgium
Hi ndenton,

NHibernate offers the possibility to create your own types.
If you implement following code, you will create MS SQL Server Timestamp support in your domain model:

Code:
using System;
using System.Data;
using NHibernate;
using NHibernate.Engine;
using NHibernate.SqlTypes;
using NHibernate.UserTypes;

namespace CompanyName.DatabaseName.DomainModel.UserTypes
{
   /// <summary />
   /// UserTypeTimestamp implements the Nhibernate BinaryType that is used to handle Nhibernate version .
   /// </summary />
   public class VersionTimestamp : IUserVersionType
   {
      #region IUserVersionType Members

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

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

      #endregion

      #region IUserType Members

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

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

      public object Disassemble(object value) {
         return 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);
         return;
      }

      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(DbType.Binary)};
            return types;
         }
      }

      #endregion

      #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
   }
}



Then use the version-tag in your XML:

Code:
<version name="PropertyName" column="ColumnName" type="CompanyName.DatabaseName.DomainModel.UserTypes.VersionTimestamp,CompanyName.DatabaseName.DomainModel" generated="always" unsaved-value="null" />



In the domain object the property needs to be of type byte[].

Using the unsaved-value attribute will tell NHibernate whether an object needs to inserted or updated, if you use GUIDs as IDs. For us this combination works perfectly and offers optimistic locking as you would expect.
A note of warning: using one-to-one relations or inheritence mapping will limit the possibilities (you can't just save any object) due the optimistic locking.


Good luck,

ds38


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 27, 2008 11:30 am 
Newbie

Joined: Fri Jun 27, 2008 11:25 am
Posts: 4
Hi,

This user type works fine in 1.2 (GA), but breaks in 2.2 (Alpha). Has anyone else experienced this?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 28, 2008 8:19 am 
Newbie

Joined: Fri Jun 27, 2008 11:25 am
Posts: 4
This doesn't work in 2.0 (alpha 2) due to a small bug. Fix is posted here http://japikse.blogspot.com/2008/06/bug ... pha-2.html


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jun 28, 2008 8:20 am 
Newbie

Joined: Fri Jun 27, 2008 11:25 am
Posts: 4
This doesn't work in 2.0 (alpha 2) due to a small bug. Fix is posted here http://japikse.blogspot.com/2008/06/bug ... pha-2.html

not sure how to get a message to the team about this.

thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 30, 2008 4:36 am 
Regular
Regular

Joined: Thu Mar 06, 2008 5:06 am
Posts: 68
Please add an entry in JIRA: http://jira.nhibernate.org


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