0

I'm trying to set up a simple association in NHibernate (this is the first project in which I want to make use of it from the ground up) - it seems like a simple, contrived, book example, but for some reason I can't get the relation to work bidirectionally.

I have a class called Contact which can contain many Addresses.

Here is the simplified Contact class:

public class Contact {

// firstName, lastName, etc, etc omitted

// ixContact is the identity value
public virtual int ixContact { get; set; }
public virtual ICollection<Address> addresses { get; set; }

}

and here is Address:

public class Address {
       public virtual int ixAddress { get; set; }
       public virtual Contact contact { get; set; }
}

here is the relevant part of the mapping file, Contact.hbm.xml:

<id name="ixContact">
    <generator class="hilo" />
</id>

<bag name="Addresses" inverse="true" cascade="save-update">
     <key column="ixContact" />
     <one-to-many class="Address />
</bag>

here is the relevant part of the Address.hbm.xml mapping file:

<id name="ixAddress">
    <generator class="hilo" />
</id>

<many-to-one name="contact" class="Contact" column="ixContact" />

Given that setup, I run the following code:

_configuration = new Configuration();
    _configuration.Configure();
    _configuration.AddAssembly(typeof(Contact).Assembly);

    _sessionFactory = _configuration.BuildSessionFactory();

    _session = _sessionFactory.OpenSession();

    new SchemaExport(_configuration).Execute(false, true, false);

    Contact firstContact = new Contact { firstName = "Joey", middleName = "JoeJoe", lastName = "Shabadoo" };

    using( ITransaction tx = _session.BeginTransaction()) {

           firstContact.Addresses = new List<Address>();
           Address firstAddress = new Address { /* address data */ };

        firstContact.Addresses.Add(firstAddress);

      _session.SaveOrUpdate(firstContact);

      tx.Commit();
    }


    _session.Close();

    _session.Dispose();

Once I run this code, the Contact is inserted into the Contact table just fine, and the Address is also inserted into the Address table, except that the Address's ixContact field is NULL, not associated with the value of the Contact's ixContact field, as I would expect.

If I explicitly specify the other side of the relation and say firstAddress.Contact = firstContact, it works fine, but I was under the impression that NHibernate took care of this automagically?

If so, what am I doing wrong? Or do I have to specify RandomContact.Addresses.Add(foo), foo.Contact = RandomContact every time?

  • So the data is fine, but your in memory entities aren't? – Vadim May 04 '11 at 18:21
  • When running the code sample above, the Address record in the database is not associated with the Contact (there is a unidirectional association from Contact->Address, but not from Address->Contact). I was under the impression (although like I said, I certainly could be wrong about this) that NHibernate handled the mirroring of the association for you so long as you specified the inverse in the mapping file. –  May 04 '11 at 18:59
  • 1
    yes, you need to set both sides of the relationship in memory. check these questions http://stackoverflow.com/q/1061179/40822 http://stackoverflow.com/questions/713637/inverse-attribute-in-nhibernate – dotjoe May 04 '11 at 20:17
  • @dotjoe I'm going to put this in an answer and mark it as "accepted" (since it is the correct answer), but if you want to convert this comment into an answer I'll mark that as accepted instead. Oh, and thanks for answering my question! :) –  May 12 '11 at 17:24

2 Answers2

0

Hmm, it looks like you're missing the call _session.Save(firstContact); before calling tx.Commit();

Jaimal Chohan
  • 8,530
  • 6
  • 43
  • 64
  • Whoops - sorry; I'm missing that in the example, but not in the actual code. Thanks for pointing it out; I will correct the question immediately. –  May 04 '11 at 17:13
0

You do need to set both sides of the relationship explicitly.