views:

195

answers:

3

Hi,

I have a table defnition as given below:

License

ClientId
Type
Total
Used

ClientId and Type together uniquely identifies a row. I have a mapping file as given below:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true">
  <class name="Acumen.AAM.Domain.Model.License, Acumen.AAM.Domain" lazy="false" table="License">
<id name="ClientId" access="field" column="ClientID" />
<property name="Total" access="field" column="Total"/>
<property name="Used" access="field" column="Used"/>
<property name="Type" access="field" column="Type"/>
  </class>
</hibernate-mapping>

If a client used a license to create a user, I need to update the Used column in the table. As I set ClientId column as the id column for this table in the mapping xml, I am getting TooManyRowsAffectedException.

could you please let me know how to set a composite key at mapping level so that NHibernate can udpate based on ClientId and Type.

Something like: Update License SET Used=Used-1 WHERE ClientId='xxx' AND Type=1

Please help.

Thanks, Mahesh

+3  A: 

You have to use a composite-id

http://nhforge.org/doc/nh/en/index.html#mapping-declaration-compositeid

Claudio Redi
+1 That is one way of doing, indeed! =)
Will Marcouiller
+2  A: 

If you primary key is composite, your mapping should reflect that, and your class needs to override Equals and GetHashCode.

Also, if ClientId is the primary key of your Client entity, you should map it as many-to-many, not just an Id.

Also, why are you specifying lazy="false"? Are you aware of the implications?

Also, why map everything with access="field"? Do the properties have some special logic?

This is a revised mapping considering everything I just wrote. Feel free to ignore those parts that don't apply :-)

<class name="Acumen.AAM.Domain.Model.License, Acumen.AAM.Domain" table="License">
  <composite-id>
    <key-many-to-one name="Client" column="ClientID" />
    <key-property name="Type" />
  </composite-id>
  <property name="Total" />
  <property name="Used" />
</class>
Diego Mijelshon
+1 Good solution, and visual example of the mapping, excellent! =)
Will Marcouiller
A: 

As the other comrades mentioned above, you have to use a composite-id, which is not a best but acceptable practice.

On the other hand, you can simply write an update interceptor and make sure your Type = 1 within it.

Here are some link about the topic to help you see clear in this.

  1. Elegant code : Implementing NHibernate Interceptors
  2. NHibernate Documentation : Interceptors
  3. Sample NHibernate IInterceptor implementation
  4. Enterprise .NET Community : NHibernate Part 2 (Scroll down to : Interceptors and Persistent Lifecycle)
  5. NHibernate Interceptor Auditing Inserted Object Id (SO question)

The main advantage of using interceptors over a composite key is that it doesn't break your DBRM and provides a definitely more flexible solution, without "polluting" your mapping file which will more precisely represent your model.

Will Marcouiller