views:

27

answers:

1

I have a simple object model of a header with multiple detail lines. I have mapped a bag property on the header object to the line class and also put a header property on the line class to set the two way relationship.

When I run my tests, using NHibernate Profiler I can see that the query is being performed, and the header and lines are fetched from the database, but the collection is always empty.

When I query for a collection of line objects directly I can get them and see the header object is correctly populated, so I know the mapping is probably OK.

The slightly non-standard aspect to this is that the line object has a compound key. (This is a legacy DB and I cannot change this), so I'm wondering if that is the problem.

Here are my classes and mappings (simplified)

  <class name="Header" table="HEADER">
    <id name="ID" column="HEAD_ID">
      <generator class="assigned" />
    </id>

    <bag name="Lines" table="BODY" order-by="BODY_LINE">
      <key column="BODY_HEADER_ID"/>
      <one-to-many class="Line"/>
    </bag>
  </class>

  <class name="Line" table="BODY">
    <composite-id>
      <key-property name="ID" column="BODY_HEADER_ID"/>
      <key-property name="Line" column="SBODY_LINE"/>
    </composite-id>
    <many-to-one class="Header" name="Head" column="BODY_HEADER_ID" />
  </class>

  public class Header {
        public virtual string ID { get; set; }
        public virtual IList<Line> Lines { get; set; }
  }

  public class Line {
        public virtual string ID { get; set; }
        public virtual int Line { get; set; }
        public virtual Header Head { get; set; }

        public override bool Equals(object obj) {
            var other = obj as Line;

            return ID == other.ID && Line == other.Line;
        }

        public override int GetHashCode() {
            return (ID + "|" + Line.ToString()).GetHashCode();
        }
    }

I can get around this by querying for the Line objects separately, but I'd like to know what I'm doing wrong.

EDIT: Ok, when I simplified things, I didn't do it very consistently. Sorry for the confusion. I have changed the mapping and class definitions to reflect things more accurately.

+2  A: 

You are mapping the same column twice (BODY_HEADER_ID), and using different three different class names for the HEADER table.

This is the correct Line mapping:

<class name="Line" table="BODY">
  <composite-id>
    <key-many-to-one class="Header" name="Header" column="BODY_HEADER_ID"/>
    <key-property name="Line" column="SBODY_LINE"/>
  </composite-id>
</class>

And of course, Line should have only that single reference to Header.

Diego Mijelshon
Also use "Inverse=true" on one side of the relationship or the other.
apollodude217
apollo is right. The bag should be inverse, and probably cascade="all" too.
Diego Mijelshon
@Diego I only see 2 class names for the HEADER table: Header and Payslip (the mapping of which is not shown). Where is the third?
apollodude217
@apollo the class has "Head" instead of "Header"
Diego Mijelshon
Thank you. I didn't know about the "key-many-to-one" mapping.
nickd
That didn't solve the problem. I think the problem might be that I don't have a value for 'Line' when joining from the Head.
nickd