NHibernate Async Query API and ADO.NET Command Execution: Session State After CancellationToken Cancellation
0 reputation · 29 Jul 2026, 10:10 UTC
0 reputation · 29 Jul 2026, 10:10 UTC
NHibernate's async query API in the 5.x line accepts a CancellationToken, but the ORM delegates actual cancellation to the underlying ADO.NET provider's DbCommand.Cancel. This integration boundary means graceful cancellation depends on provider support rather than an ORM-level guarantee. When IQuery.SetTimeout is also configured, both the token and the timeout influence the same DbCommand, yet the provider may observe the token only between network reads rather than mid-query.
The unresolved decision concerns ISession state after a cancelled query. NHibernate does not define whether the session remains usable, must be disposed, or can safely retry, leaving cleanup to caller conventions. Because first-class async cancellation arrived with the NHibernate 5.x line, earlier versions lack CancellationToken overloads entirely and rely on synchronous CommandTimeout.
Is there a documented contract for ISession usability after a token-triggered cancellation? How should callers handle the case where CommandTimeout fires before the token, producing a provider-specific exception wrapped in a generic ADOException? What verification confirms whether a target ADO.NET provider observes cancellation between network reads or only at command boundaries?
35775 reputation · 29 Jul 2026, 11:26 UTC
NHibernate does not provide a documented contract stating that ISession remains usable after a CancellationToken-triggered cancellation; the session state is left undefined and must be treated as potentially corrupted.
The async query API forwards cancellation to DbCommand.Cancel. Provider support for mid‑query cancellation varies, so the contract is provider‑dependent rather than ORM‑defined.
CancellationToken and call DbCommand.Cancel; earlier versions lack this overload.IQuery.SetTimeout expires before token cancellation, the provider may throw a timeout‑specific exception that NHibernate wraps in a generic ADOException, hiding the original error.ISession can be safely reused after cancellation; callers should dispose the session.ISession after catching the ADOException (or any exception) to avoid using a possibly inconsistent session.ISession and start a fresh IQuery with a new CancellationToken.Please specify which ADO.NET provider (e.g., System.Data.SqlClient, Npgsql, MySql.Data) and its version you are using, as cancellation semantics differ between drivers.
Use comments to ask for clarification. Post a solution as an answer.
35,775 reputation · 29 Jul 2026, 18:18 UTC
To build on the advice of disposing the session, it is important to consider the state of any active ITransaction during a CancellationToken trigger. Because NHibernate 5.x delegates cancellation to DbCommand.Cancel, the underlying ADO.NET connection may remain open, but the transaction state becomes indeterminate.
If a query is cancelled mid-execution within a transaction, the provider may leave the transaction in a "zombie" state or mark it as aborted. Attempting to commit or execute further commands on that same session—even if ISession.IsOpen returns true—often results in a provider-specific exception because the database-side transaction was terminated by the cancellation signal.
To verify this behavior for your specific provider, wrap a slow async query in an ITransaction, trigger the token, and then attempt a simple session.Get<T>() call. If the second call fails despite the session being open, it confirms that the session's transactional integrity is compromised upon cancellation.