Search code examples
c#.netnhibernateassociationsmappings

Creating and retrieving associated mappings in NHibernate


Say I have two persistent classes Cat and Hat. Let's imagine that the relationship between the two is bidirectionally one-to-many, as in a Cat can have many different Hats, and we can traverse the mapping in both directions. In order to create an association between an instance of each class, I should be able to, and correct me if I'm wrong, do the following:

Cat whiskers = new Cat();
Hat redHat = new Hat();
redHat.Id = 1; // normally assigned by generator but this makes example more explicit
whiskers.Hats.Add(redHat);
catService.Save(whiskers);
hatService.Save(redHat);

With that in mind, should I not be able to retrieve the Cat which is associated with redHat by doing the following?

Hat hat = hatService.FindById(1); // redHat has Id 1
Cat cat = hat.Cat; // cat should be whiskers

Unfortunately, when I try to use this technique, cat results as a null object in that last line. I'm guessing I am missing something in my one-to-many mapping in Cat.hbm.xml, or at least I hope it's something that simple. Here's what it currently looks like:

<set name="Hats" inverse="true">
  <key column="Id"/>
  <one-to-many class="Hat"/>
</set>

I have no mapping in Hat.hbm.xml since adding one resulted in a "duplicate mapping" error. I read the Hibernate documentation on association mappings, but still can't get this working. What am I doing wrong?

Complete mapping files below:

Cat.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="Domain"
               namespace="Domain">

  <class name="Cat" table="cats" lazy="true">

    <id name="Id">
      <generator class="increment" />
    </id>

    <property name="Name" />

    <set name="Hats" inverse="true">
      <key column="Id"/>
      <one-to-many class="Hat"/>
    </set>

  </class>

</hibernate-mapping>

Hat.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="Domain"
               namespace="Domain">

  <class name="Hat" table="hats" lazy="true">

    <id name="Id">
      <generator class="increment" />
    </id>

  </class>

</hibernate-mapping>

Edit

I believe the problem was that I was not initializing the ISet<Hat> value in the Cat class. However, I've run into a new problem. When I try to access the associations, I get this error:

Could not initialize proxy - no Session.

I figured this would be easily avoided if I created a method in my DAO where I could wrap it in a session like this:

public Cat GetRelatedCat(Hat hat)
{
    Cat cat;
    using (ISession session = HibernateUtil.GetSessionFactory().OpenSession())
    {
        cat = hat.Cat;
    }
    return cat;
}

This yields the same "no session" error. I'm stumped.


Solution

  • I solved the problem by creating a SessionManager which allows me to open a Session, perform any transactions and access any collection proxies within the Session singleton, and then close the Session.