Fluent NHibernate NonUniqueObjectException

I have a parent entity with a collection of children entities that need to be updated from a webservice pretty much every time I access that parent entity. I figured I could just do a Clear() on the collection and then add the list of entities I receive from the web service. It seems to work fine when the entities I receive do not have the same Id as any of the ones I just cleared but if any of the Ids are the same I get the NonUniqueObjectException. Since I am clearing them shouldn't they be deleted before the new entities are inserted? Why does it matter if the Ids are the same?

preguntado el 25 de abril de 13 a las 00:04

Can we see some code to see what you have tried? -

3 Respuestas

Even though your IDs are the same, the objects themselves are not actually the same. You can verify this by doing yourobject. GetHashCode() in the watch.

NHibernate thinks that this is a new database object and wants to insert it.

You need to keep the original object and copy the new values into it.

You can copy these values manually, property by property - but I would recommend making this dynamic, so that you dont need a method for every object type.

You can write your own dynamic method with reflection or use a third party mapper... Try AutoMapper https://github.com/AutoMapper/AutoMapper

Be careful when copying the properties accross. If your chil objects have any further children which are also mapped, you will run into the same problem again.

Respondido 25 Abr '13, 00:04

So what you are saying is that the objects I cleared are still sticking around? So when I get new objects with the same Id, it tries to insert them before deleting the old ones? I have my mapping set to cascade delete all orphans. I thought that was supposed to make sure that if I got rid of any objects in the collection it would be removed from the database as well. - Pérez

hi. I see you have solved your issue below. However, deleting and reinserting seems a bit odd - but if it works, it works! Just out of curiosity - are you generating your IDs yourself? Because I would have thought that if your database was generating your IDs, then it would have thrown an error... it would not normally allow you to insert a row with an identity, unless you have called.. "SET IDENTITY_INSERT yourTableName ON" (this is syntax for Sql Server) I would always make sure that I am updating data, instead of deleting and reinserting - seems more stable to me. - Mike S

The Ids are coming from a remote web service, I am not generating them in my database myself. And your answer might actually be more efficient because it would mean less database calls if I just iterate through my existing entities and update instead of just blowing them all away then flushing to the db and then re-inserting and hitting the db again. If I update and add new ones I think nhibernate will do it all in one trip. - Pérez

After clear method, save parent object. so it removes children from database and session. then add children and save once again.

Respondido 25 Abr '13, 06:04

This did not work. Instead I did a flush() and it all started working. But your answer somehow gave me the idea to try that. Thanks! - Pérez

In your mapping enable Cascade.AllDeleteOrphan() If you miss this. - Jugal Panchal

After the initial deletion of children objects with a clear() I had to do a flush() before re inserting the new children (that may have the same Ids). Then I did a save and everything worked.

Respondido 25 Abr '13, 15:04

Just a bit more info on why this works. It is because of the order that nhiberate does things. The SQL statements are issued in the following order: 1-all entity insertions, in the same order the corresponding objects were saved using ISession.Save(), 2-all entity updates, 3-all collection deletions, 4-all collection element deletions, updates and insertions, 5-all collection insertions, 6-all entity deletions, in the same order the corresponding objects were deleted using ISession.Delete() - Pérez

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.