ADR-0006: NHibernate as the primary ORM¶
Decision
This page records a decision and its status. A Proposed decision is not binding; an Accepted decision is binding on the Factory until amended or superseded.
- Status: Accepted
- Date: 2026-01-01
- Deciders: Data Architect, Backend Lead
- Tags: persistence, data, orm
Reviewed 2026-10-09 — retained, clarified
- Disposition: retain.
- Verified: NHibernate is the persistence of BaseTemplate, the five SaaS templates, the Orleans messaging outbox writer and all nine DerechHaLev services; canonical ADR-0100 also assumes NHibernate for SaaS services.
- Clarification: "Document-shaped data uses Cosmos DB" is a profile option, not a requirement; no Cosmos integration was inspected. Per-context store ownership is specified in the ownership map, not implied by this ADR.
- Provenance:
Dateis the 2026-06-17 bulk-commit value.
Context¶
Transactional metadata (aggregates, registries, lifecycle state) is stored in Azure SQL / PostgreSQL with a database-per-service model (see Data Architecture). The platform needs a mature ORM that supports rich domain mapping for DDD aggregates, row-level tenant filtering, and second-level caching, and is already grounded in the ConnectSoft.Extensions.* data libraries and templates.
Decision¶
Use NHibernate as the primary ORM for transactional stores. Tenant isolation is enforced through tenantId participation in indexes and row-level filtering in NHibernate; each store has a single owning service.
Consequences¶
Positive¶
- Rich mapping for DDD aggregates and value objects; mature filtering and caching.
- Consistent data-access pattern baked into templates.
Negative / trade-offs¶
- Mapping/configuration learning curve; care needed for query performance.
Neutral¶
- Document-shaped data uses Cosmos DB rather than the relational ORM.
Alternatives considered¶
| Alternative | Why not chosen |
|---|---|
| Entity Framework Core | Viable, but platform libraries/templates are standardized on NHibernate. |
| Dapper / micro-ORM | Insufficient domain-mapping and filtering for aggregate-heavy domains. |