views:

2332

answers:

3

NHibernatians!

I have a table [dbo].[Wibble] and another table [dbo].[WibbleExtended].

[Wibble] is the main table and [WibbleExtended] is an optional table where some other fields are stored. There are far fewer entries in the [WibbleExtended] table than the main [Wibble] table. I think this was done back in the day to cure some space issues (Wibble has many rows and WibbleExtened has many columns).

The ID for each table is the same and comes from an external source.

I.e.

[dbo].[Wibble].[WibbleId]

and

[dbo].[WibbleExtended].[WibbleId]

are identical and is how the two tables relate.

N.B. I can't change the schema. I'm shoe-horning this onto a legacy system that I have almost no control over.

Searching around it seems that one-to-one mappings are problematic and the prevailing wisdom is to use two many-to-one mappings.

My mappings currently are:

<class name="Wibble" table="Wibble" >
   <id name="Id" column="WibbleId" type="Int32">
      <generator class="assigned"/>
   </id>

   <many-to-one name="WibbleExtended" class="WibbleExtended" column="WibbleId" not-null="false" cascade="all"/>
</class>

And

<class name="WibbleExtended" table="WibbleExtended" >
   <id name="Id" column="WibbleId" type="Int32">
        <generator class="assigned" />
   </id>

   <many-to-one name="Wibble" class="Wibble" column="WibbleId" not-null="true" />     
 </class>

The problem with this is I'm getting errors such as

System.IndexOutOfRangeException: Invalid index n for this SqlParameterCollection with Count=n.

I've looked around and this does look like the correct strategy, it's just falling at the final hurdle.

Is the problem the id generator? Other aspect of the mapping?

Free mince pie for the correct answer.

EDIT: Ok - here's what I did to solve this via @James Gregory.

  1. Moved the unit tests from the WibbleExtended tests to the Wibble test class and made the necessary modifications.

  2. Added the following to the Wibble.hbm.xml

    <join table="WibbleExtended" optional="true">
         <key column="WibbleId"/>
         <property name="Blah1" column="Blah1" type="String" length="2000" not-null="false" />
         <property name="Blah2" column="Blah2" type="String" length="1000" not-null="false" />    
    </join>
    
  3. Added the corresponding properties to the Wibble POCO.

  4. Deleted all code relating to WibbleExtended.

  5. Run tests, all passed, checked in. Build passed. Went for an xmas beer (hence it's been a couple of days before I updated this! :-))

+5  A: 

Have you considered using the Join element that was introduced in NHibernate 2.0? This element allows you to join multiple tables to form one entity; that relationship can also be optional.

James Gregory
Thanks. Am reading now.
IainMH
Worked perfectly! Thanks James.
IainMH
+1  A: 

Check out this link: http://www.hibernate.org/hib_docs/nhibernate/html/inheritance.html

The "joined subclass" mapping in particular I think you will find helpful (assuming WibbleExtended inherits from Wibble).

AlexCuse
+6  A: 

The error you are getting:

Invalid index n for this SqlParameterCollection with Count=n.

is due to two properties mapped to the same column. Use insert=false and update=false in one of the two.

reference http://groups.google.com/group/nhusers/browse_thread/thread/84830b1257efd219

jalchr