Skip to content

SAIF.Framework.Data.NHibernate operations and processes

This page catalogs the operations this library performs and, for each, the step-by-step logic that implements it.

Operation catalog

Operation Intent Trigger Inputs Outputs Rules Tables SQL
Build and cache an NHibernate configuration for a connection string Build (or reuse a cached) NHibernate Configuration/ISessionFactory for a given connection string. IConfigurationFactory.GetConfiguration(connection, batchSize, showSql) Connection string, batch size, show-SQL flag Cached PersistenceConfiguration — — —
Obtain a unit of work for a connection string Build (or reuse a cached) ISessionFactory and hand back a NHibernateUnitOfWork bound to a fresh session. IUnitOfWorkFactory.GetUnitOfWork(connectionString, batchSize, showSql) Connection string, batch size, show-SQL flag NHibernateUnitOfWork bound to a freshly opened ISession/IStatelessSession — — —
Unit of work transaction lifecycle Manage the begin/commit/rollback lifecycle of a unit of work's transaction. Consumer calls Begin()/Commit()/Rollback()/Dispose() on a NHibernateUnitOfWork — Transaction committed or rolled back; session cleared or disposed BR-001, BR-002 — —
Repository CRUD and query operations (stateful vs stateless divergence) Perform generic persistence operations against a mapped entity, diverging by session strategy. Consumer calls Add/Update/Delete/Query/Get/Load/SystemDate on a Repository<TEntity> Entity instance, entity ID, or none (for Query/SystemDate) Entity persisted/retrieved; behavior differs by session strategy BR-003, BR-004 — SQL-004
Oracle sequence based ID generation (Imaging domain) Obtain the next value of an Oracle sequence directly, bypassing the mapped-entity ID-generation path. Consumer calls GetNextImageId/GetNextTowId/GetNextImageAffiliationId extension methods IRepository<Image> / IRepository<ImageSystem> / IRepository<ImageAffiliation> instance long — next sequence value — image, IMGSYS, IMAGE_AFFILIATION SQL-001, SQL-002, SQL-003

Process flow diagram

The following diagram visualizes the primary operational flow from configuration through transaction commit.

flowchart TD
    Start([Consumer requests unit of work]) --> Cfg[Build/cache NHibernate Configuration]
    Cfg --> UoW["Build/cache ISessionFactory; open Session/StatelessSession"]
    UoW --> Begin[Begin transaction]
    Begin --> Ops[Repository Add/Update/Delete/Query/Get/Load]
    Ops --> Decision{Success?}
    Decision -->|Yes| Commit([Commit transaction])
    Decision -->|No| Rollback([Rollback transaction])

Build and cache an NHibernate configuration for a connection string

A consumer requests an NHibernate Configuration for a connection string through IConfigurationFactory.GetConfiguration(connection, batchSize, showSql), typically invoked from UnitOfWorkFactoryBase.BuildSessionFactory.

Field Value
Trigger IConfigurationFactory.GetConfiguration(connection, batchSize, showSql) call
Inputs Connection string, batch size, show-SQL flag
Outputs A cached PersistenceConfiguration (wraps NHibernate Configuration + a serialized-config file path)
Primary components Factories/ConfigurationFactoryBase.cs, Factories/OracleConfigurationFactory.cs, Factories/SqlServerConfigurationFactory.cs

Steps — Build and cache an NHibernate configuration for a connection string

  1. Look up connection in the static ConcurrentDictionary<string, PersistenceConfiguration> Configurations; if present, return it (cache hit).
  2. On cache miss, call CreateConfiguration(connection, batchSize, showSql).
  3. Attempt to deserialize a previously-serialized Configuration from a binary file at {assemblyDirectory}\{GetConfigurationFileName()} (Oracle.config or SqlServer.config) using BinaryFormatter.
  4. On any exception (including file-not-found): fall back to null.
  5. If no serialized configuration was found, build a new one via the engine-specific GetNewConfiguration(formatSql) override, which configures Fluently.Configure() with the engine driver and scans this assembly (and any ClassMapAssemblyList assemblies) for ClassMap<T>/.hbm.xml mappings.
  6. Set Environment.ConnectionString, Environment.BatchSize, Environment.ShowSql on the configuration.
  7. Return a PersistenceConfiguration wrapping the built Configuration and the serialized-config file path.

Failure and edge-case behavior — Build and cache an NHibernate configuration for a connection string

  • Deserialization failures are silently swallowed (caught Exception, configuration set to null, forcing a fresh build).

Obtain a unit of work for a connection string

A consumer requests a NHibernateUnitOfWork bound to a freshly opened session through IUnitOfWorkFactory.GetUnitOfWork(connectionString, batchSize, showSql).

Field Value
Trigger IUnitOfWorkFactory.GetUnitOfWork(connectionString, batchSize, showSql)
Inputs Connection string, batch size, show-SQL flag
Outputs A NHibernateUnitOfWork bound to a freshly opened ISession/IStatelessSession
Primary components Factories/UnitOfWorkFactoryBase.cs, Factories/OracleUnitOfWorkFactory.cs, Factories/OracleStatelessUnitOfWorkFactory.cs, Factories/SqlServerUnitOfWorkFactory.cs

Steps — Obtain a unit of work for a connection string

  1. Lock the static SessionFactories dictionary (per-process synchronization).
  2. Get-or-add an ISessionFactory for connectionString via BuildSessionFactory, which resolves the PersistenceConfiguration (see Build and cache an NHibernate configuration for a connection string) and calls Configuration.BuildSessionFactory().
  3. Call the engine-specific CreateUnitOfWork(factory) override:
  4. OracleUnitOfWorkFactory/SqlServerUnitOfWorkFactory → CreateSessionUnitOfWork (stateful ISession via factory.OpenSession(), wrapped in StatefulSessionStrategy).
  5. OracleStatelessUnitOfWorkFactory → CreateStatelessSessionUnitOfWork (IStatelessSession via factory.OpenStatelessSession(), wrapped in StatelessSessionStrategy).
  6. Build the matching ISessionHelper (OracleSessionHelper/SqlServerSessionHelper) via BuildSessionHelper.
  7. Return a new NHibernateUnitOfWork(sessionStrategy, sessionHelper).

Unit of work transaction lifecycle

Once a consumer has obtained a NHibernateUnitOfWork, it manages the transaction boundary explicitly through Begin(), Commit(), and Rollback().

Field Value
Trigger Consumer calls Begin() after obtaining a NHibernateUnitOfWork
Outputs Transaction committed or rolled back; session cleared
Primary components UnitOfWork/NHibernateUnitOfWork.cs

Steps — Unit of work transaction lifecycle

  1. Begin(): check IsTransactionInProgress() (transaction IsActive, WasCommitted, or WasRolledBack).
  2. If true: throw InvalidOperationException("There is a transaction already in progress.") (BR-001).
  3. Otherwise: call Session.Clear() then Session.BeginTransaction(IsolationLevel.ReadCommitted).
  4. Repository operations (Add/Update/Delete/Query/Get/Load) are performed via repositories obtained from GetRepository<TEntity>(), all sharing this unit of work's Session (BR-005).
  5. Commit(): get the current ITransaction.
  6. If !transaction.IsActive: throw InvalidOperationException("You must call Begin() on the unit of work before you can commit.") (BR-002).
  7. Otherwise: call transaction.Commit() then Session.Clear().
  8. Rollback(): if the transaction IsActive, call transaction.Rollback(); then always call Session.Dispose().
  9. Dispose(): standard dispose pattern; if not already disposed and Session is not null, call Session.Dispose().

Failure and edge-case behavior — Unit of work transaction lifecycle

  • Begin() and Commit() both enforce state invariants via InvalidOperationException (BR-001, BR-002).
  • Rollback() disposes the session unconditionally, even if no transaction was active.

Repository CRUD and query operations stateful vs stateless divergence

A consumer performs generic persistence operations against a mapped entity through a Repository<TEntity>; the underlying behavior diverges depending on whether the unit of work uses a stateful or stateless session strategy.

Field Value
Trigger Consumer calls Add/Update/Delete/Query/Get/Load/SystemDate on a Repository<TEntity>
Outputs Entity persisted/retrieved; behavior differs by session strategy
Primary components Repositories/RepositoryBase.cs, Sessions/StatefulSessionStrategy.cs, Sessions/StatelessSessionStrategy.cs, SessionHelper/SessionHelperBase.cs

Steps — Repository CRUD and query operations

  1. RepositoryBase<TEntity>.Add(entity) → Session.Add(entity).
  2. Stateful: ISession.SaveOrUpdate(entity) (Sessions/StatefulSessionStrategy.cs).
  3. Stateless: IStatelessSession.Insert(entity) (Sessions/StatelessSessionStrategy.cs).
  4. RepositoryBase<TEntity>.Update(entity) (BR-003):
  5. Stateful: no-op (empty method body in StatefulSessionStrategy.Update, since dirty-checking auto-flushes on commit).
  6. Stateless: explicit IStatelessSession.Update(entity) call.
  7. RepositoryBase<TEntity>.Delete(entity) → Session.Delete(entity) in both strategies.
  8. RepositoryBase<TEntity>.Query() → Session.Query<TEntity>() (LINQ to NHibernate) in both strategies.
  9. RepositoryBase<TEntity>.Get(id) / Load(id):
  10. Stateful: ISession.Get<TEntity>(id) / ISession.Load<TEntity>(id) (lazy proxy).
  11. Stateless: both Get and Load delegate to IStatelessSession.Get<TEntity>(id) (no lazy-proxy support in stateless mode).
  12. RepositoryBase<TEntity>.SystemDate → SessionHelper.SystemDate (BR-004, SQL-004) → runs the engine-specific date SQL and falls back to DateTime.Now if the result is null/min/max.

Failure and edge-case behavior — Repository CRUD and query operations

  • No exceptions are raised by the CRUD/query steps themselves; the only fallback behavior is SystemDate's local-clock substitution (BR-004).

Oracle sequence based ID generation Imaging domain

A consumer calls one of three extension methods to obtain the next value of an Oracle sequence directly, bypassing the mapped-entity ID-generation path.

Field Value
Trigger Consumer calls GetNextImageId, GetNextTowId, or GetNextImageAffiliationId extension methods on IRepository<Image>/IRepository<ImageSystem>/IRepository<ImageAffiliation>
Outputs long — next sequence value
Primary components Repositories/Imaging/ImageRepositoryExtensions.cs

Steps — Oracle sequence based ID generation, Imaging domain

  1. Cast the IRepository<T> to the concrete Repository<T> to access its internal Session.
  2. Run Session.CreateSqlQuery("select {sequence}.nextval from dual") — direct SQL escape hatch (not entity-mapped), one of three:
  3. image_seq (SQL-001, image)
  4. tower_seq (SQL-002, IMGSYS)
  5. image_affiliation_seq (SQL-003, IMAGE_AFFILIATION)
  6. Convert.ToInt64(query.UniqueResult()) and return.

Failure and edge-case behavior — Oracle sequence based ID generation, Imaging domain

  • This is the one "direct SQL escape hatch" case in this library — session-level CreateSqlQuery, Oracle-only (uses NEXTVAL FROM DUAL syntax).
  • ImageAffiliation.Id also has a native NHibernate sequence generator (GeneratedBy.Native("IMAGE_AFFILIATION_SEQ")), making SQL-003 a parallel/redundant ID-acquisition path to the mapping's own generator.*

Database interactions

The following table summarizes which operations read from or write to the database.

Operation SQL Tables Type
Repository CRUD and query operations (stateful vs stateless divergence) SQL-004 — (DUAL pseudo-table / no table) Read
Oracle sequence based ID generation (Imaging domain) SQL-001, SQL-002, SQL-003 image, IMGSYS, IMAGE_AFFILIATION Read

Cross-cutting failure behavior

  • Deserialization of a previously-serialized Configuration silently swallows any exception and falls back to a fresh build, rather than surfacing the failure.
  • Begin()/Commit() enforce state invariants via InvalidOperationException (BR-001, BR-002); Rollback() disposes the session unconditionally.
  • SystemDate silently substitutes local DateTime.Now when the database query returns null/min/max (BR-004).

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Factories/ConfigurationFactoryBase.cs
  • Factories/OracleConfigurationFactory.cs
  • Factories/SqlServerConfigurationFactory.cs
  • Factories/UnitOfWorkFactoryBase.cs
  • Factories/OracleUnitOfWorkFactory.cs
  • Factories/OracleStatelessUnitOfWorkFactory.cs
  • Factories/SqlServerUnitOfWorkFactory.cs
  • UnitOfWork/NHibernateUnitOfWork.cs
  • Repositories/RepositoryBase.cs
  • Sessions/StatefulSessionStrategy.cs
  • Sessions/StatelessSessionStrategy.cs
  • SessionHelper/SessionHelperBase.cs
  • Repositories/Imaging/ImageRepositoryExtensions.cs