Can this have anything to do with the fact that you have a surrogate key in the storeproducts table ?
What happens if you remove this surrogate key column Id, and put the primary key on the combination of the product_id and store_id columns ?
I believe that, if you want to have a surrogate key on the storeproducts table, you'll have to create yet another entity.
If you want to use the surrogate key, you'll have to use the idbag mapping.
How does your Product class and mapping look like ?
I see that you specify the 'inverse' attribute in your mapping of the Products collection in the Store entity.
If you do this (and thus you have a bi-directional association), then you should add the Store to the Stores collection of the product as well.
Since -from the NH documentation- :
Changes made only to the inverse end
of the association are not persisted.
This means that NHibernate has two
representations in memory for every
bidirectional association, one link
from A to B and another link from B to
A. This is easier to understand if you
think about the .NET object model and
how we create a many-to-many
relationship in C#:
category.Items.Add(item); // The category now "knows" about the relationship
item.Categories.Add(category); // The item now "knows" about the relationship
session.Update(item); // No effect, nothing will be saved!
session.Update(category); // The relationship will be saved
The non-inverse side is used to save
the in-memory representation to the
database. We would get an unneccessary
INSERT/UPDATE and probably even a
foreign key violation if both would
trigger changes! The same is of course
also true for bidirectional
one-to-many associations.
You may map a bidirectional
one-to-many association by mapping a
one-to-many association to the same
table column(s) as a many-to-one
association and declaring the
many-valued end inverse="true".
This means, that only one of the ends should be inverse.
Adding a Product to a store, should be done like this:
public class Store
{
public void AddProduct( Product p )
{
if( _products.Contains (p) == false )
{
_products.Add (p);
p.AddStore(this);
}
}
}
public class Product
{
public void AddStore( Store s )
{
if( _stores.Contains (s) == false )
{
_stores.Add (s);
s.AddProduct(this);
}
}
}
(Very important to check whether the collection already contains the item to be added; otherwise you'll end up in an infinite loop.
As Matthieu says, the only case where you wouldn't want to set inverse = true is where it does not make sense for the child to be responsible for updating itself, such as in the case where the child has no knowledge of its parent.
Lets try a real world, and not at all contrived example:
<class name="SpyMaster" table="SpyMaster" lazy="true">
<id name="Id">
<generator class="identity"/>
</id>
<property name="Name"/>
<set name="Spies" table="Spy" cascade="save-update">
<key column="SpyMasterId"/>
<one-to-many class="Spy"/>
</set>
</class>
<class name="Spy" table="Spy" lazy="true">
<id name="Id">
<generator class="identity"/>
</id>
<property name="Name"/>
</class>
Spymasters can have spies, but spies never know who their spymaster is, because we have not included the many-to-one relationship in the spy class. Also (conveniently) a spy may turn rogue and so does not need to be associated with a spymaster. We can create entities as follows:
var sm = new SpyMaster
{
Name = "Head of Operation Treadstone"
};
sm.Spies.Add(new Spy
{
Name = "Bourne",
//SpyMaster = sm // Can't do this
});
session.Save(sm);
In such a case you would set the FK column to be nullable because the act of saving sm would insert into the SpyMaster table and the Spy table, and only after that would it then update the Spy table to set the FK. In this case, if we were to set inverse = true, the FK would never get updated.
Best Answer
The inverse attribute must not be set to true ...
You use the inverse attribute to specify the 'owner' of the association. (An association can have only one owner, so one end has to be set to inverse, the other has to be set to 'non inverse'). (Owner:
inverse=false
; Non-owner:inverse=true
)In a one-to-many association, if you do not mark the collection as the inverse end, then NHibernate will perform an additional UPDATE. In fact, in this case, NHibernate will first insert the entity that is contained in the collection, if necessary insert the entity that owns the collection, and afterwards, updates the 'collection entity', so that the foreign key is set and the association is made. (Note that this also means that the foreign key in your DB should be nullable).
When you mark the collection end as 'inverse', then NHibernate will first persist the entity that 'owns' the collection, and will persist the entities that are in the collection afterwards, avoiding an additional UPDATE statement.
So, in an bi-directional association, you always have one inverse end.