views:

380

answers:

3

We have a entity with a many-to-many collection mapped as a lazy loaded bag. When we load up the entity, the collection is not loaded - great. Now we want to add a new entity to that collection. As soon as we do this, the collection is loaded up.

How do we add the new entity without loading up the whole collection (the collection is large)?

A: 

The reason for this behavior is that you are referencing your collection when you Add() an new item to it. This reference triggers the lazy-load.

I've found it best to avoid explicit many-to-many mappings in NHibernate. I normally use two one-to-many associations to a third entity, which works like a link table. Make sure you set the many sides of the relationship to inverse="true". You can then directly perform:

session.Save(new LinkEntity(leftSideInstanceOrProxy, rightSideInstanceOrProxy);

Another benefit is that there's normally information about the relationship that you want to save, which can also go in the new entity.

James L
When there is no extra information needed, this approach makes you domain model persistence dependent
Paco
Yes, I don't want to add a non business related class to my model for this. However, I've done a spike and I can't do it any other way. Am I right in thinking NHibernate does not support this? If so, does anyone know why not?
JontyMC
How about second level cache?
dario-g
A: 

I had the same problem.

You just have to create the middle entity and do two one-to-many relations.

If you checked the statements it generates to update a many-to-many relation, you wouldn't use it anyways. When you add a new item to a many-to-many relation the relation in first loaded (I think this generates one select statement), then you update that relation and do a commit. This things happen:

Delete is performed for every object in the array (maybe it's one delete statement or N delete statements, I don't remember)

All objects are reinserted into the database (N insert statements + the new one).

If you make a lot of updates to the many-to-many relation then many-to-many mapping is not for you. You can use many-to-many on object's that don't change or don't change very often (because of all the deletes and reinserts).

You should make 3 objects (let's say User, Post, Vote - which is a USER_POST middle table). Create primary keys for all of those tables (even for USER_POST). Create a surrogate key, and make a constraint for USER_ID, POST_ID to be uniqe for USER_POST table. Map it as normal one-to-many, many-to-one (parent-child, child-parent) relations and that's it.

dmonlord
+1  A: 

If you don't want to change your domain model, you could execute SQL directly to update the m-m link table (either using an Nhibernate Query or executing a parameterised stored proc).

Also, note that you won't be able to use the Add() operation (otherwise NH will automatically trigger the lazy load). Instead, consider calling a suitably named method on your Repository class.

Vijay Patel