I'll try to explain the problem precisely.
There's an entity A
which has a one-to-many relation with B
(a collection).
In addition, entity B
has a many-to-many
relation with an entity C
.
When I first store a transient object of type A
, both A
and related transient B
entity instances associated with A
are correctly created in the database, but transient C
instances associated with B
aren't created.
The many-to-many association is mapped in both sides of the association as follows (mapping-by-code approach):
// Mapping for collection of Entity C on Entity B
@class.Set
(
entityB => entityB.EntityCList,
map =>
{
map.Table("EntitiesBInEntitiesC");
map.Cascade(Cascade.All);
map.Key(key => key.Column("EntityBId"));
map.Inverse(false);
},
map => map.ManyToMany(relMap => relMap.Column("EntityCId"))
);
// Mapping for collection of Entity B on Entity C
@class.Set
(
entityB => entityB.EntityBList,
map =>
{
map.Table("EntitiesBInEntitiesC");
map.Cascade(Cascade.All);
map.Key(key => key.Column("EntityCId"));
map.Inverse(true);
},
map => map.ManyToMany(relMap => relMap.Column("EntityBId"))
);
Also, when entity B
and entity C
is instantiated when they're both transient objects yet, I add the one of entity B
on the collection of entity C
and viceversa.
Finally, the transaction ends successfully: I mean that the entity A
and B
, and their association are stored in the database as expected.
Why the entity C
associations aren't persisted in the database? What am I doing wrong?
NOTE: I'm using the latest version of NHibernate 3.x series.
NOTE 2: I've just profiled the SQL Server database and the inserts into the m:n table are never executed!
I'd like to answer my own question in order to share how easy was solving the problem but how hard took understanding what originated the problem.
Because I was going to add some kind of validation logic, I was adding a flush entity event listener:
Since the model mapping was right, both Radim Köhler (the other answerer) and me were trying to figure out why the many-to-many relation wasn't being stored into the database.
Commenting the whole listener binding solved the problem.
Well, the problem isn't the whole listener binding but not calling the default flush implementation, or yeah, just not adding the whole listener if it's not really needed (my case, I was just trying some kind of interception that I'm not needing anymore!).
Either you need to provide how entity flushes or use the default one, but leaving it blank (empty event listener) will prevent some entities to correctly flush:
Hopefully this answer will help others to solve similar problems...