tags:

views:

100

answers:

3

What would be your approach with NHibernate to do the following:
When Comment is inserted into DB, and its property Text is inserted into column Text (due to a mapping), insert into column TextHash a hash of this property value.

It seems trivial if I map TextHash, but how should I do this without mapping it?
I do not need it in the domain model, its a DB-level optimization (I would use computed HashBytes if not for the length limit).

A: 

Well, if you don't want to use the property, declare it private and calculate it when you set the text property. It's not exactly "without mapping it", but you won't see it when you're using the class (disclaimer: advice based on Hibernate, as opposed to NHibernate).

Other than that, you could always write a trigger, although I'd personally much rather add a private field and be done with it.

Tomislav Nakic-Alfirevic
I know I can use private one, but it is not exactly persistence ignorant. So that's kind of goes against NH strengths as I see them.
Andrey Shchekin
I'm afraid I fail to see the downside of declaring a private field. Semantically, declaring it that way, you basically _are_ saying it's a " local implementation detail", it's "not to be used from outside of the entity", and the rest of the application remains blissfully ignorant of the calculated field. You need to place the hashing logic _somewhere_, and I can only think of two places: the model and the database. Anyway, feel free to disregard. :)
Tomislav Nakic-Alfirevic
I see the third location, examples of which are IUserType or IInterceptor and which does not tie hashing algorithm directly to the entity. I just do not see what extensibility point of NHibernate applies to my use case.
Andrey Shchekin
Seems like I'm overgeneralising when assuming hibernate and nhibernate are twin implementation. I'm interested in hearing what sort of conclusion the question will come to.
Tomislav Nakic-Alfirevic
I answered with approach that I ended up using.
Andrey Shchekin
A: 

Here's a suggestion: As far as I know you can't access a column in your DB using NHibernate if it there no mapping defined for it. To prevent other parts of your application to see this field of your class you can define its access as field in your mapping so that it can be private an no one knows that it exists but NHibernate: In your class:

private string _textHash

In your mapping:

<property name='_textHash' column='TextHash' access='field' />
Beatles1692
Well, this is practically the same thing Tomislav suggests. It has same problems: ties entity to hashing algorithm, which really an implementation detail, ties entity to the DB structure. Also, a private field no one uses has a large probability of being removed by Resharper-wielding developers.
Andrey Shchekin
+1  A: 

There are some similar questions, such as this one:
Unmapped Columns in NHibernate?

However, IInterceptor seems like an overkill for a change in a single entity insert. And EventListeners are less than perfectly documented and also somewhat too complex for a single column.

So I have decided on the solution that I see both as most reusable and most local:

  <property name="Text" type="StringWithMD5HashUserType">
    <column name="Text" length="20000" not-null="true" />
    <column name="TextHash" length="32" not-null="true" />
  </property>

Where StringWithMD5HashUserType is ICompositeUserType that reads Text from first column, but writes both Text and its Hash (I do not add the code of StringWithMD5HashUserType because it is way too long, but essentially very simple).

Andrey Shchekin