0

I have a client who's been running a program of mine for a couple of years now who started getting strange errors. My application throws exceptions with this in it:

Cannot insert duplicate key in object

Since I didn't touch the code in literally years, this confused me a lot. And it only happened sometimes.

After A LOT of debugging and pulling out my hair, I figured out what is happening.

In the code that adds items to the database, I call session.SaveOrUpdate.

I can't recall a specific reason i chose this over the expected session.Save method, but let's continue. (i am changing this for the client's code though).

So what seems to be happening is that the SaveOrUpdate is re-using existing object's ID's and completely overriding the existing item. My code throws an error, but the new item is saved to the DB and there is no trace of the original record any longer. In my nhibernate mapping documents I am using the hilo generator for object IDs.

I am guessing this is only happening because there are now enough items in the DB to make the IDs restart or something, i don't know. I do have an audit table that has/had A LOT of records in it. 10,000's. But i truncated that table to make backups smaller. (could this have causes this problem).

I'm trying to find out if anyone can conclusively state if the SaveOrUpdate does for some reason re-use existing IDs or why changing the call to just Save works now. If this is a known issue i will sleep easy, if not, i need to further debug to see if there isn't still some situation where my client will lose data.

My code is running Nhibernate 3.3.3.4000, which was the latest code when i wrote this app.

Update 1

Session.Save is also re-using ID's.

I keep getting duplicate key errors, when inserting new records. But not every time, only some times. So it's quite random, which makes it hard to debug.

2 Answers 2

1

NHibernate users have requested a general purpose method that either saves a transient instance by generating a new identifier or update the persistent state associated with its current identifier. The SaveOrUpdate() method now implements this functionality.

http://nhibernate.info/doc/nh/en/index.html#manipulatingdata-updating-detached)

Based on this, you're hypothesis regarding the behaviour of SaveOrUpdate() would stand if NH allocated the object's key before testing whether or not it's 'transient' or 'persisted'. I.e. the key generator allocates a key that happens to be used and then the save or update logic favours update as it determine's the object is 'persistent'. I would be surprised if this is what's actually happening as it seems quite a basic mistake to make.

If you enable logging, you'll be able to determine whether this is actually the case or not.

Sign up to request clarification or add additional context in comments.

3 Comments

The records that are being overriden have been create months/years ago, not inside the current session or transaction. Before flush is even called, right after session.save, the ID of the new record is already allocated an ID of a previously existing item. Session.save is also doing this.
...and that's what generates the duplicate key error, I guess? I can understand that behaviour. What I don't understand is how existing data is being over-written.
you and me both. If i step over the code line by line as it executes, i can see the call to session.save assigns an id to my new record. If i go to sql management studio and query the data with that ID, it is a completely different record. Then, after the transaction commits, the original record is completely gone, even if I search for it based on other values. One thing i probably should also mention is that there is an ADO exception, which states that there is a primary key violation, but i was catching that exception and commiting anyway (yeah i know bad). I fix that to roll back
1

I spent many hours to try and figure out this issue, but i sort of gave up in the end.

My solution, which seems to work so far, was to change the nhibernate id generator class from hilo to native.

This did require me to export and re-import all my data so that I could rebuild the tables however, so may not be a great solution for others who find this post, unless they change the identity on the tables manually.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.