Concept

Architecture overview

The shared typed pipeline under all three access modes, the package layout, and how the dialect layer keeps code portable.

ORM Current 3 min read Updated

One pipeline, three modes#

Raw SQL (KMQL), Entity and Repository modes are front ends. All of them go through the same execution layer inside DatabaseContext:

text
Raw SQL (KMQL)   Entity (fluent + SaveChanges)   Repository (derived from method names)
        \                    |                              /
         '------------- typed command layer ---------------'
                              |
          markup resolution -> parameter binding -> dispatch
                              |
                database specification (dialect) for the engine in use
                              |
                    ADO.NET driver -> database
                              |
                    result mapping to typed objects

Because parameter binding, result mapping and query dispatch are written once, the three modes do not have separate code paths. Execution characteristics, such as performance, transactions and (in Enterprise) auditing, do not change with the abstraction you chose.

The dialect layer#

Each supported database has a database specification. It knows how to quote identifiers, write boolean literals, paginate, concatenate strings, format dates, create savepoints and so on. Two features use it:

  • KMQL markup resolves tokens such as {{T:}}, {{C:}}, {{PAGINATE}} or {{NOW}} by calling the active specification. Where a method already exists on the specification, the resolver reuses it. See the KMQL reference.
  • Entity and Repository commands generate SQL through the same specification, so their statements are correct for each engine without per-provider code.

Your application code names a provider in exactly one place: the line that connects the context (for example UsePostgreSql(...)).

Positional-parameter drivers#

Some drivers accept only positional ? parameters (for example HCL's Informix driver). Kiwi ORM wraps those connections so @name parameters are rewritten to positional ones, cached per statement text, with each parameter's type taken from its value. Your code is the same as for every other provider.

SQL caching#

Parsed repository method names and the SQL generated for them are cached, so derived queries are analysed once. The cache can be inspected with the repository monitor.

Packages#

The solution is split so you take only what you use:

Layer Contents Edition
Abstractions Attributes, context and the auditing hooks (IAuditAdapter, audit contexts) Free
Core The pipeline, entity and command layer, the database specifications for all engines, KMQL Free
Cte Managed CTE builders and per-engine providers Commercial
Source generators Roslyn generators for entity boilerplate Free
Tooling CLI Entity generation and migrations (runs in the Kiwi shell) Free
Repository, Repository.DependencyInjection Repository mode and DI registration Commercial
Auditing adapters Ready-made audit trail storage in a relational database (all 11 engines) or MongoDB Commercial

The assemblies are listed in Packages and assemblies.

Where it is used#

Kiwi ORM Core is the data-access layer under Kiwi Fabric, Kiwi Flow and Kiwi Vault, which use it for their own registries and for the databases they connect to. Kiwi Fabric's registry store can therefore run on any of the engines Kiwi ORM supports.