0

I am effectively doing the following:

session.Save(newParent);

newChild = new Child(parent: newParent);

session.Save(newChild);

session.Load<Parent>(newParent.Id).Children.Count //0 - calling Get has the same result

However, if before the Load call, I call session.Refresh(newParent), the Children will load correctly. So it is clearly caching the parent before it has any children, then not updating the cache with the new child when it is added.

Parent Mapping:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="MyApp.Models.Entities.Parent,MyApp" table="[Parent]" lazy="true" batch-size="100">
    <id name="ParentId" column="ParentId" type="int">
      <generator class="native" />
    </id>
    <bag name="Children" inverse="true" lazy="true" cascade="delete" batch-size="100">
      <key column="ParentId" />
      <one-to-many class="MyApp.Models.Entities.Child,MyApp" />
    </bag>
  </class>
</hibernate-mapping>

Child Mapping:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="MyApp.Models.Entities.Child,MyApp" table="[Child]" lazy="true" batch-size="100">
    <id name="ChildId" column="ChildId" type="int">
      <generator class="native" />
    </id>
    <many-to-one name="Parent" column="ParentId" cascade="save-update" />
  </class>
</hibernate-mapping>

My question is 1) Am I doing something wrong or is this the default behaviour? 2) If not, what is the cleanest way to solve this?

This issue actually only occurs in the test project and I can mod the underlying test architecture to do a force refresh behind the scenes in this case, but I would like to fully understand what is going on before implementation a solution.

Using NHibernate 3.2 and everything is wrapped in a ReadCommitted transaction.

Alistair
  • 1,939
  • 2
  • 22
  • 31
  • Question is similar to this one: http://stackoverflow.com/questions/1206452/hibernate-onetomany-with-mappedby-parent-child-relationship-and-cache-problem – Alistair Jan 27 '12 at 00:27
  • 1
    Why are you saving them separately? Parent is your root aggregate and should be responsible for the Child. – Phill Jan 27 '12 at 00:31
  • Phill, this is done throughout the application, however from the test project (which is where the issue exists) there is infrastructure used to create a parent or child which is all one line method calls which creates a new object and calls session.Save on it. Cascade could be used to solve my problem, but it would involve complicating the API calls the tests make to the infrastructure and it would involve a lot changes to the infrastructure code so it understands the relationships and how to handle them. Basically, it is cleaner and simpler to not use cascade to save in this case. – Alistair Jan 27 '12 at 03:15
  • 1
    Unfortunately then there's no other way than to call Refresh to get the entity changes. Unless there's some secret magic that I'm unaware of. – Phill Jan 27 '12 at 03:33
  • Thanks, it's good to know this is expected functionality. If no-one else responds I will use refresh calls behind the scenes to hide this nuance from my tests. – Alistair Jan 27 '12 at 05:10
  • It's unfortunate. I'm working on a 10yo+ legacy system which I implemented NH in over a year ago, we are just doing it step by step, re-mapping everything and updating the API to suit, similar scenario to what you're in except we're updating our API. Slow process but we don't want to cut corners. – Phill Jan 27 '12 at 05:20
  • So you want to use the active record pattern, more or less – Nexus Jan 27 '12 at 08:58

2 Answers2

2

Where are you adding the child to the parent's Children collection? Setting the reference from newChild.Parent to newParent does not add newChild to newParent's Children collection, you have to do that. That's why it's a common practice to declare the collections as private members (mapped using an access strategy) and write AddChild and RemoveChild methods that maintain the relationship on both sides.

Jamie Ide
  • 48,427
  • 16
  • 81
  • 117
  • Nowhere. I was hoping that NHibernate would recognise that a child had been added and that the cached parent would need to be refreshed / the new child would have to be added to the children list. It looks like I need to refresh this manually – Alistair Jan 29 '12 at 22:40
0

1) Am I doing something wrong or is this the default behaviour?

Somewhat, the correct way to handle this would be to add them in one go and using cascade. However, this is not appropriate for my particular situation.

2) If not, what is the cleanest way to solve this?

There is no particularly clean way to solve this. I have baked refreshing the parent in the cache into the test architecture.

Thanks Jamie and Phill.

Alistair
  • 1,939
  • 2
  • 22
  • 31