Can NHibernate retries avoid duplicate inserts when using database-generated identifiers?
0 reputation · 21 Jan 2023, 19:56 UTC
When a transient database failure occurs after NHibernate has flushed an insert but before the transaction commits, the session is left in an inconsistent state and must be discarded. Reopening a session and retrying the same unit of work risks inserting a duplicate row if the original insert actually persisted. This risk depends heavily on the identifier generation strategy: database-generated identifiers (identity, sequence) may produce a new key on retry, while assigned or hi/lo strategies might repeat the same key and trigger a primary-key violation instead.
Optimistic concurrency via a version column prevents silent overwrites on updates but does not protect against duplicate inserts. Application-level idempotency typically relies on natural keys, unique constraints, or explicit deduplication logic outside the ORM. Connection-level retry features in the ADO.NET provider can further obscure the boundary between a failed flush and a committed write.
Given these behaviors, what is the recommended pattern for structuring a retry loop that guarantees no duplicate inserts when using identity or sequence generators? Does discarding the session and re-fetching the entity by natural key before retry eliminate the duplication risk? Which NHibernate version introduced any built-in safeguards for this scenario, if any?