Question

I am pretty new to NHibernate and I'm trying to create a mapping file to extend a data model project. The particular table I am mapping is called AttributeDef in the following image, the column ControlType actually relates to a lookup in the table called Code (yes, I know - there should be an FK constraint but this sort of thing is quite common in this project so please ignore the obvious howlers and focus on the question). In most cases tables which reference Code also have a column which contains the ID from the table CodeSet as the key in Code is, almost inevitably, a composite key, but not in this case presumably because the original author figured "Hey they're all from the same codeset so what's the point?".

Table structure relating to problem

Now if there was a column in AttributeDef which contained the CodeSet value then the mapping wouldn't be much of a problem. The mapping for the Code entity looks like this:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="Activus.DataModel" namespace="Activus.DataModel">

  <class name="Code" table="Code" mutable="false">

    <composite-id name="CompositeCodeId" class="CompositeCodeId">
      <key-property name="CodeId" column="CodeId"/>
      <key-property name="CodeSet" column="CodeSet"/>
    </composite-id>

    <property name="Description" column="Description" type="string" length="100" not-null="true"/>
    <property name="ExternalRef" column ="ExternalRef" type ="string" length ="256" not-null ="true"/>
    <property name="InternalRef" column ="InternalRef" type ="string"  not-null ="false"/>
    <many-to-one name="CodeSet" class="CodeSet" column="CodeSet" not-null="true" insert="false" update="false"/>

  </class>

</hibernate-mapping>

Therefore if there was a column in AttributeDef for the CodeSet value (notionally called FormControlCodeSet in this example) then in my AttributeDef mapping file I would include

<many-to-one name="ControlType" class="Code" not-null="false">
  <column name="ControlType" />
  <column name="FormControlCodeSet" />
</many-to-one>

And all should be well. The problem is that to add that column to AttributeDef would be very invasive as I would then have to make a LOT of other changes to accommodate this and that would increase the risk factor of the change I'm making to a point which might well be unacceptable (from the client's point of view given their time frame).

So, much as it's a horrible, horrible thing to contemplate, Is it possible to substitute the line

<column name="FormControlCodeSet" />

With a (whisper it) hard coded value? That value hasn't changed in a decade and isn't likely to anytime soon but it would get us past this change and would highlight the need to scope out and implement the inclusion of the extra column. I recognise how dreadful this is but unfortunately a lot of this database isn't really that well suited to ORM despite it's being shoe-horned in anyway.

Was it helpful?

Solution

You do not have to whisper requirements, when working with NHiberante. Because cooperation with legacy DB (i.e. fixed DB schema) is pretty standard, NHibernate does support many different settings.

One of these is a pair of (substitutional) settings: "column" vs "formula". The first takes the column as is, the second could do whatever we need. Take column, columns, pass a constant. So:

<many-to-one name="ControlType" class="Code" not-null="false">
  <column name="ControlType" />
  <!-- let's replace this --> 
  <!--<column name="FormControlCodeSet" />-->

  <!-- 1) with a constant number 123-->
  <formula>123</formula>
  <!-- 2) with a constant string 'constantString' -->
  <formula>'constantString'</formula>
</many-to-one>

Not sure if the FormControlCodeSet constant should be int or string, but as shown above, either option is possible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top