2

When my domain model have a composite key in the database I will get an exception when forgetting to override Equals/GetHashCode

NHibernate.MappingException: composite-id class must override Equals():

Why does it not give me the same error when I have a non composite ID?

Stig
  • 1,974
  • 2
  • 23
  • 50

1 Answers1

3

NHibernate uses the primary key value of your class in its internal state-tracking engine to identify that instance.

When you have a single primary key property in your domain, NHibernate will use the value returned by the property as the key value, calling GetHashcode and Equals on the value, using the primary key much like you would use it in a Dictionary<TKey,TValue> instance.

When there are multiple primary key properties forming a composite key, NHibernate has no trivial way to get a key value it can use. It requires you define how to determine equality between two instances, effectively turning the instance into its own key much like it would be in a HashSet<T>.

If you haven't overridden Equals and GetHashCode on your type to use your composite key values, it does not reflect the "equality" used by the data-model (two rows being equal if they have the same primary key) and NHibernate cannot be certain it is tracking the correct entities; this is why the exception occurs.

You can find out an overview of composite keys and more information on clever ways to deal with them here.

Paul Turner
  • 38,949
  • 15
  • 102
  • 166
  • I see. NH uses the mapping to find the property for a single primary key and gets the hascode on this. This is OK, since it is a simple type and have a well defined hash code. But couldn’t' it do the same for composite keys, or will the “computed” hash code be too weak? – Stig Jan 04 '12 at 15:24
  • .. and how can NH use HashSet when dealing with single primary keys and Equals/GetHashCode has not be overridden? – Stig Jan 04 '12 at 15:26
  • You can imagine that NHibernate uses a `Dictionary` when you have a simple primary key, with the key being the primary key value, and a `HashSet` when there is a composite key used. It is possible that NHibernate could create an internal type to contain the primary key values, but currently it does not. – Paul Turner Jan 04 '12 at 16:17
  • That's my point. If it uses a Dictionary for a simple primary key why not do the same for the composite key so we don't need to write equals/hashcode – Stig Jan 17 '12 at 08:19
  • Okay, but you would have to express some way of determining equality and the hash code; NHibernate could try and guess a way of doing this depending on the types used, but there is no foolproof way of handling this situation without some kind of configuration. NHibernate obtains that "configuration" through a custom implementation of `Equals` and `GetHashCode`. – Paul Turner Jan 17 '12 at 10:46