Troubleshooting

Common problems

Connection, mapping, repository, migration and engine-specific issues in Kiwi ORM, with causes and fixes.

ORM Current 4 min read Updated

BeginTransaction() throws "connection is not set" or "not open"#

The context must be connected first. Call .Connect() after CreateContext, and keep the context alive for the duration of the work.

An entity is not found by the context#

Entities and stored-procedure classes are registered by group. The class needs [DbContextObject("Group")], and the context's RegisterDbObjects() must call AddDbObjects("Group"). A stored procedure class is recognised because of [StoredProcInfo].

SaveChanges writes nothing#

Change tracking relies on SetAndNotify. A property implemented as a plain auto-property is not tracked. Use the pattern in Entity mode or the source generator.

A repository method with a long return type fails#

Declare count methods as int. A long return type currently fails inside the repository proxy (an Int32 to Int64 cast).

GetReference() returns default values#

By design: GetReference(id) returns an entity with only its key populated and no database call. It is not a lazy-loading proxy. Use it only to set a foreign key, and load the entity with FindById if you need its data.

A repository or auditing method does not exist#

Repository mode and the ready-made audit adapters are Commercial features. The extension methods (such as EnableDefaultAuditing) only appear when the commercial package is referenced. The auditing hooks (IAuditAdapter and UseAuditAdapter) are free, so you can write your own adapter. See Audit data access. See Editions and features.

Firebird: names do not match#

Firebird folds unquoted names to upper case, while Kiwi quotes names as written. Create tables with quoted names that match your mapping, and write queries with {{T:}} and {{C:}}, which quote for the engine.

Informix: parameters behave differently#

Some Informix drivers accept only positional ? parameters. Kiwi rewrites @name parameters for you. The HCL driver (Informix.Net.Core) is 64-bit and needs no client SDK; the older IBM driver is 32-bit only and needs the Client SDK. The ODBC-based driver cannot prepare CREATE DATABASE.

Migration: a rename became drop and add#

Renames are never guessed. The tool writes a Possible rename note instead. Re-run model-add-change with --rename "Orders=Sales;Items.Name=Title" to emit RENAME statements that keep data, keys and indexes. Some engines cannot rename in place, and in those cases the tool refuses rather than risk data:

  • Firebird cannot rename tables in place.
  • Microsoft Access cannot rename tables or columns.
  • DB2 cannot rename a table that takes part in a foreign key (SQL0750N). A column rename drops and re-creates the indexes on it.

Migration: destructive statements are commented out#

This is deliberate. DROP TABLE and DROP COLUMN ship commented out. Review them and uncomment only the ones you intend to run.

Migration: a column could not be changed#

  • Microsoft Access cannot make a NOT NULL column nullable with SQL (a note says so).
  • Firebird and SAP HANA cannot shrink a column. Rolling back a widening leaves the column wide and says so in a note.
  • SQLite cannot alter a default and emits a note.

model-verify reports drift#

The live database no longer matches schema.json: someone changed it outside a migration. Either bring the database back in line, or capture the change as a new migration block. Do not edit blocks that have already been applied. If schema.json itself has a merge conflict, run model-rebuild to regenerate it from schema-changes.sql. Note the snapshot reflects the declared model, not the actual database state.

model-rollback refuses to run#

--confirm is required, and only the most recently applied block can be rolled back. If existing rows would no longer fit the previous column definitions, add --allow-data-loss after checking what the database will truncate or reject.

Views are missing from the generated entities#

The scaffold step does not read views from the database. Map views manually as entities, or query them with Raw SQL mode.

Recursive CTE stops early#

MaxRecursion bounds the depth. Raise it if your hierarchy is deeper than the value you set.

Benchmark numbers differ from the published ones#

Published figures come from one environment. Re-run with -c Release on your own data. See Performance.