views:

32

answers:

3

I am working with nHibernate, and trying make sense of bag collections. My data structure is relatively straight-forward...

Entry:

<class name="Entry">
<id name="id" column="EntryId">
    <generator type="guid.comb"/>
</id>
    <property name="Name" column="Name"/>
<bag name="Results" table="Results" cascade="all">
    <key column="EntryId" />
    <one-to-many class="Result"/>
</bag>
</class>

Result:

<class name="Result">
<id name="id" column="ResultId">
    <generator type="guid.comb"/>
</id>
<property name="Score" column="Score" />
<many-to-one name="Entry" class="Entry" cascade="all" />
</class>

What I would like to do, which doesn't seem to be working, is the following:

Entry entry = new Entry();
entry.Name = "Name";
// have tried saving at this point to:
// dbSession.SaveOrUpdate(entry);
Result result = new Result();
result.Score = 100;

entry.Results.Add(result);
dbSession.SaveOrUpdate(entry);

It seems to be creating the entry record in the database, but not the result record. In my database, I have EntryId as a foreign key in the Result table. Similarly, I would like to be able to remove the result object from the collection, and have it persist to the database. I thought the cascade feature took care of this, but not sure what I have done wrong...

EDIT

I now have it adding the result object into the database, but delete does not seem to work:

Entry entry = Entry.Load(id);
entry.Results.Remove(result);
dbSession.SaveOrUpdate(entry);

I have tried adding cascade="all-delete-orphan", but this seems to remove both parent and children. I just want it to delete the one entry object from the database??

A: 

To add to a collection you need to explicitly save the child object when it is added. Ditto when you delete an object from a collection.

So you would do:

entry.Results.Add(result);
session.Save(result);
session.Save(entry);
session.Flush();

The foreign key also has to be nullable. The reason why you have to do this is NHibernate has to save the child first with no association to the parent. Then when the parent is saved the foreign key column on the child gets updated with the parent's Id, creating the relation. This is because NHibernate may not have the needed parent id key value until the second operation (parent is saved) has completed.

I guess you have this part figured out.

Delete works the same way for different reasons - remove the child from the parent collection, then delete the child explicitly, then update the parent:

entry.Results.Remove(result);
session.Delete(result);
session.Update(entry);
session.Flush();

You removed result from the collection and updated the entry. That only tells Nhibernate to delete the relationship between the entry and the result - you never actually deleted the result object itself.

Sisyphus
I thought so too, but this is not the case. My answer is provided.
mickyjtwin
A: 

I notice that, in your collection, you have defined the FK column as:

<key column="EntryId" />

But you are not overriding the column in your many-to-one, which means you have two different columns (Entry and EntryId) for the same relationship.

This might be it or not... but it doesn't hurt to check :-)

Diego Mijelshon
A: 

In the end, this came down to my hbm file mappings not being correct.

Entry.hbm.xml

Result.hbm.xml

I originally had cascade="all-delete-orphan" on the many-to-one mapping, which was not correct. What happened was that all children and the parent record was being deleted.

I can now add and remove with the following:

Result r = new Result();
Entry entry = new Entry();
// AddResult method sets the Entry object of the Result
// result.Entry = this;
entry.AddResult(r);
session.SaveOrUpdate(entry);

To delete:

entry.Results.Remove(result);
session.SaveOrUpdate(entry);
mickyjtwin