Mahesh
Mahesh

Reputation: 1689

NHibernate update using composite key

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

Upvotes: 1

Views: 1553

Answers (3)

Claudio Redi
Claudio Redi

Reputation: 68400

You have to use a composite-id

http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-compositeid

Upvotes: 3

Will Marcouiller
Will Marcouiller

Reputation: 24132

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.

Upvotes: 1

Diego Mijelshon
Diego Mijelshon

Reputation: 52725

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>

Upvotes: 2

Related Questions