SequelizeDotNet.Providers.Db2
0.1.0
dotnet add package SequelizeDotNet.Providers.Db2 --version 0.1.0
NuGet\Install-Package SequelizeDotNet.Providers.Db2 -Version 0.1.0
<PackageReference Include="SequelizeDotNet.Providers.Db2" Version="0.1.0" />
<PackageVersion Include="SequelizeDotNet.Providers.Db2" Version="0.1.0" />
<PackageReference Include="SequelizeDotNet.Providers.Db2" />
paket add SequelizeDotNet.Providers.Db2 --version 0.1.0
#r "nuget: SequelizeDotNet.Providers.Db2, 0.1.0"
#:package SequelizeDotNet.Providers.Db2@0.1.0
#addin nuget:?package=SequelizeDotNet.Providers.Db2&version=0.1.0
#tool nuget:?package=SequelizeDotNet.Providers.Db2&version=0.1.0
SequelizeDotNet
A database-first, explicit-DDL ORM for .NET — inspired by Sequelize.js, rebuilt around .NET's runtime type system.
SequelizeDotNet lets you point at an existing database — SQL Server, PostgreSQL, SQLite, MySQL/MariaDB, Oracle, or DB2 — and immediately query, insert, update, and delete against it with real, strongly-typed CLR objects, without hand-writing a single entity class and without a code-first migration model deciding what your schema should look like. The schema is read live from the database; the entity types are generated at runtime via System.Reflection.Emit; and every structural change (adding a column, renaming a table, dropping an index) happens only when you call an explicit, clearly-named method — never through automatic diffing or guessing.
Table of Contents
- Why this exists
- Design philosophy
- Feature list
- What's new — beyond Sequelize
- How it compares to other .NET ORMs
- Supported databases & testing status
- Installation
- Quick start
- CLI reference
- Documentation
- Roadmap / known limitations
- Contributing
- Acknowledgments
- License
Why this exists
Sequelize.js has been one of the most influential ORMs in the Node.js ecosystem for over a decade — its model of belongsTo/hasMany/belongsToMany associations, lifecycle hooks (beforeCreate, afterUpdate, ...), and a query builder that stays close to SQL without hiding it behind an impenetrable abstraction, shaped how a whole generation of JavaScript developers think about relational data access. See Associations and Hooks in the official docs.
.NET's dominant ORM story — Entity Framework Core — takes a fundamentally different, code-first stance: you declare DbContext/entity classes at compile time, and migrations describe how the database should change to match your code. That's an excellent model for greenfield projects where the code owns the schema. It's a much worse fit for the extremely common case of an existing, already-owned database — a legacy system, a database another team or another codebase (perhaps in another language entirely) already controls, or simply a team that doesn't want application code dictating schema changes.
SequelizeDotNet exists to bring Sequelize's database-first ergonomics — and its hook/association vocabulary — to .NET, while leaning into what .NET can do that JavaScript can't: emit real CLR types at runtime, so a table introspected five seconds ago already has a genuine, reflectable, strongly-typed class backing every row — no code generation step, no dotnet ef command, no rebuild.
Design philosophy
Three decisions run through the entire codebase:
- Database-first, always. The database's live schema — read via
ISchemaIntrospector— is the single source of truth. The library never infers what your code "should" look like from a model class; the model comes from the database, not the other way around. - Explicit DDL, never automatic diffing. Every structural change is one clearly-named method call —
RenameColumnAsync,AddColumnAsync,DropTableAsync, and so on — that a developer invokes deliberately, with destructive operations additionally requiringforce: trueand locked out in production unless explicitly overridden. There is nosync({ alter: true })-style "make the database look like my model, however that requires" operation, because that class of feature is exactly what makes automatic schema sync dangerous in production. The philosophy in one sentence: "never decide on your own — only when explicitly told." - Runtime types, not code generation.
EntityTypeFactoryemits one real .NET type per table viaSystem.Reflection.Emit, cached per-table inModelRegistrywith a lazy, thread-safe, single-emission guarantee. Change a column type in the database, and the very next query against that table gets a freshly emitted type reflecting it — no rebuild, no restart, no generated.csfile to keep in sync (though an optional POCO code generator exists for teams that want compile-time IntelliSense on a schema they consider stable).
Feature list
Schema & introspection
- Live schema introspection (
ISchemaIntrospector) across 6 dialects — tables, columns, indexes (including primary keys), and foreign keys (including composite keys) - Explicit DDL commands: create table, add/drop/rename column, change column type, rename table, drop table — every destructive operation gated behind
force: trueand a production lock - Schema snapshot + diff (
snapshot/diffCLI commands) for detecting drift between two points in time - Automatic hot-reload:
SchemaWatcherpolls, diffs, and re-emits/removes runtime entity types with zero application restart
Querying
- A fluent, string/operator-based query builder (
Where,OrderBy,Take,Skip) — deliberately not LINQ-expression-based, because the target type is emitted at runtime and has no compile-time member to reference (the same reason Sequelize itself usesOp.eq/Op.inrather than a typed query DSL) - Nested eager loading:
Include("Author.Publisher.Country")— any number of foreign-key hops deep, each level resolved as a separate, cached,IN (...)-filtered follow-up query — never a JOIN - Many-to-many eager loading through an explicit junction table:
IncludeMany("Tags", "dbo", "PostTags", "FK_PostTags_Posts", "FK_PostTags_Tags")— the junction table and both of its foreign keys are named explicitly, matching the project's explicit-over-inferred philosophy - A raw-SQL escape hatch that still materializes rows into the table's registered runtime type
Data manipulation
Insert/Update/Delete, each returning the exact row as stored (including server-computed defaults and identity values) in as few round trips as each dialect allows- Bulk insert (
CreateManyAsync, mirroring Sequelize'sModel.bulkCreate()) — a single multi-rowINSERTon SQL Server/PostgreSQL/DB2, a batched insert + range re-select on SQLite/MySQL, and a sequential loop on Oracle (which has no multi-rowVALUESsyntax) - Sequelize-style lifecycle hooks:
BeforeCreate/AfterCreate,BeforeUpdate/AfterUpdate,BeforeDestroy/AfterDestroy— a handler throwing in aBefore*hook aborts the operation before any SQL runs DbTransactionthreaded through every data-touching API (queries, schema commands, data commands), so any sequence of calls can be wrapped in one ambient transaction
Connections & change notifications
- Built-in read/write connection routing (
IConnectionRouter): round-robin read replicas, a dedicated write primary, and aStatementIntentClassifierthat inspects raw SQL to route it correctly — addressing a long-standing class of bugs in JS-ecosystem ORMs where raw queries silently bypass replica routing - Change Data Capture push notifications (SQL Server):
CdcChangeWatcherpollscdc.fn_cdc_get_all_changes_*and raises a C# event with materialized Insert/Update/Delete rows — subscribe once, get called back as changes land, no polling code of your own
Code generation
- Optional immutable C#
recordPOCOs generated straight from a schema snapshot, for teams that want IntelliSense over a schema they consider stable - OpenAPI 3.0.3 document generation — component schemas plus a conventional CRUD path set, straight from the introspected schema
- GraphQL SDL generation — one object type per table plus a
Queryroot, straight from the introspected schema
Tooling
- A full
dotnet toolCLI (sequelizedotnet) covering every one of the above:db:pull,snapshot,diff,codegen,codegen-openapi,codegen-graphql,schema *,data insert|bulk-insert|update|delete,watch,watch-cdc— every command accepts--dialectto target any of the 6 supported databases
What's new — beyond Sequelize
SequelizeDotNet isn't a line-for-line port. A few things exist here that Sequelize itself doesn't have, mostly because .NET's runtime and type system make them possible in the first place:
| # | Addition | Why it matters |
|---|---|---|
| 1 | Real CLR types, emitted at runtime via System.Reflection.Emit |
Sequelize model instances are dynamic JS objects; here, every row is a genuine, reflectable .NET type with real properties — generated fresh from the live schema, with no code-generation step or .d.ts drift to manage. |
| 2 | force: true + production lock on every destructive DDL call |
Sequelize's sync({ alter: true }) is widely discouraged for production precisely because it guesses what change you meant. SequelizeDotNet never guesses — every structural change is an explicit, named call, and destructive ones require an explicit override to even run outside development. |
| 3 | Read/write routing that also understands raw SQL | Sequelize's read replication support has had recurring reports of raw queries bypassing the read pool. StatementIntentClassifier inspects raw SQL's leading keyword specifically so that escape hatch stays correctly routed too. |
| 4 | Zero-restart schema hot-reload | SchemaWatcher detects drift and swaps the runtime entity type for a changed table — atomically, versioned — without restarting the process. |
| 5 | SQL Server CDC-based push notifications | Most ORMs, Sequelize included, have no built-in Change Data Capture consumption at all. CdcChangeWatcher turns SQL Server CDC into a subscribable C# event. |
| 6 | GraphQL & OpenAPI generation straight from the DB schema | No separate modeling step: introspect once, generate a GraphQL SDL schema or an OpenAPI 3.0 document directly from what the database already knows. |
| 7 | Nested + many-to-many Include, always JOIN-free |
Every eager load — however deep, however many-to-many hops involved — is a separate, cacheable, debuggable round trip. Nothing is ever hidden behind an opaque generated JOIN plan. |
| 8 | One dialect SPI, six real relational databases | SQL Server, SQLite, PostgreSQL, MySQL/MariaDB, Oracle, and DB2 all sit behind the same IDialect contract from day one — see testing status for exactly how far each has been verified. |
How it compares to other .NET ORMs
This is a young, single-maintainer project going up against tools with years (in EF Core's case, over a decade) of production hardening. Here's an honest comparison, not a sales pitch:
| Capability | SequelizeDotNet | EF Core | Dapper | NHibernate | ServiceStack.OrmLite | linq2db |
|---|---|---|---|---|---|---|
| Primary workflow | Database-first, runtime types | Code-first (database-first via scaffolding exists but is a secondary path) | Micro-ORM, you write the SQL | Database-first or code-first (XML/Fluent mapping) | Code-first, POCO-based | Code-first, POCO-based |
| Entity types | Emitted at runtime, no compile step | Compile-time C# classes | Your own POCOs | Compile-time C# classes | Compile-time C# classes | Compile-time C# classes |
| Schema changes at runtime, no rebuild | ✅ (hot-reload) | ❌ (migrations + rebuild) | N/A (no schema layer) | ❌ | ❌ | ❌ |
| Explicit-only destructive DDL guard | ✅ (force + prod lock) |
⚠️ (migrations can be reviewed, but nothing stops an auto-generated destructive migration from running) | N/A | ⚠️ | ⚠️ | ⚠️ |
| Built-in read/write replica routing | ✅ | ❌ (application/infra responsibility) | ❌ | ❌ | ❌ | ❌ |
| Built-in CDC consumption | ✅ (SQL Server) | ❌ | ❌ | ❌ | ❌ | ❌ |
| GraphQL/OpenAPI generation from schema | ✅ | ❌ (separate tooling, e.g. Hot Chocolate, needed) | ❌ | ❌ | ❌ | ❌ |
| Compile-time LINQ queries | ❌ (string/operator-based, like Sequelize) | ✅ | ❌ | ✅ (LINQ provider) | ⚠️ (typed SQL builder, partial LINQ) | ✅ |
| Multi-database support | 6 dialects, 1 SPI | Many, via provider packages | Any ADO.NET provider (you write dialect-specific SQL yourself) | Many, via dialect classes | Many, via provider packages | Many, via provider packages |
| Maturity / production track record | New (v0.1.0), unproven | Extremely mature, Microsoft-backed | Extremely mature, minimal surface area | Very mature (ported from Java Hibernate) | Mature | Mature |
| Learning curve | Low if you know Sequelize | Moderate–high | Very low | Moderate–high | Low–moderate | Moderate |
If your codebase owns its schema and you want compile-time-checked LINQ, EF Core is very likely the better default choice today — it's mature, Microsoft-supported, and has an enormous ecosystem. SequelizeDotNet is aimed at the specific case where the database is the source of truth, you want real typed objects without a migrations pipeline, and you'd rather work the way Sequelize.js taught a generation of developers to work.
Supported databases & testing status
Every dialect implements the exact same IDialect contract (introspection, DDL, query translation, data commands), but not every dialect has been exercised against a real running database. Here's the honest state, updated as of this release:
| Dialect | Implemented | Live-tested | Notes |
|---|---|---|---|
| SQL Server | ✅ | ✅ Exhaustive | Primary development/test target — 80+ live tests against SQL Server LocalDB, covering every data type, every query operator, schema drift, hot-reload, transactions, hooks, nested/many-to-many Include, and bulk insert. |
| SQLite | ✅ | ✅ Exhaustive | Second live-tested dialect — 60+ live tests against temp-file databases, same coverage breadth as SQL Server. |
| PostgreSQL | ✅ | ⚠️ Unit-tested only | Query translator verified at the unit level; no live PostgreSQL instance has been available to verify end-to-end behavior yet. |
| MySQL / MariaDB | ✅ | ⚠️ Unit-tested only | Same as above. |
| Oracle | ✅ | ⚠️ Unit-tested only | Same as above. Also: no multi-row INSERT ... VALUES syntax, so bulk insert falls back to a sequential loop — see docs. |
| DB2 (LUW) | ✅ | ⚠️ Unit-tested only | Same as above. |
Change Data Capture (watch-cdc, SQL Server-only) is a special case: SQL Server Express — including LocalDB, this project's live test environment — does not support CDC at all (confirmed directly: sys.sp_cdc_enable_db fails with error 22988 on Express edition). The pure logic (LSN comparison, capture-instance validation) is unit-tested, and the correct-error-on-Express behavior is live-tested, but full end-to-end capture behavior needs a Standard/Enterprise/Developer-edition instance to verify — not yet available.
Total, as of this release: 223 automated tests, 0 failures. Run dotnet test from the repository root to reproduce.
Installation
# Pick the dialect(s) you need
dotnet add package SequelizeDotNet.Core
dotnet add package SequelizeDotNet.Providers.SqlServer
# ...or .Providers.Sqlite / .Providers.Postgres / .Providers.MySql / .Providers.Oracle / .Providers.Db2
# Optional: code generation (POCOs / OpenAPI / GraphQL)
dotnet add package SequelizeDotNet.Codegen
# Optional: the CLI, as a local dotnet tool (recommended — pins the CLI version per-repo)
dotnet new tool-manifest # if you don't already have one
dotnet tool install --local SequelizeDotNet.Cli
Quick start
using SequelizeDotNet.Core.Querying;
using SequelizeDotNet.Core.EntityGeneration;
using SequelizeDotNet.Core.DataCommands;
using SequelizeDotNet.Providers.SqlServer;
using Microsoft.Data.SqlClient;
var dialect = new SqlServerDialect();
var registry = new ModelRegistry();
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
// Query — the "Posts" runtime type is emitted on first use, from the live schema
var engine = new QueryEngine(dialect, registry);
var query = QueryEngine.Query("dbo", "Posts")
.Where("AuthorId", QueryOperator.Equal, 42)
.OrderBy("CreatedAt", descending: true)
.Include("FK_Posts_Authors") // nested: "FK_Posts_Authors.FK_Authors_Publishers"
.IncludeMany("Tags", "dbo", "PostTags", "FK_PostTags_Posts", "FK_PostTags_Tags");
var rows = await engine.ToListAsync(query, connection);
foreach (var row in rows)
{
var author = row.Includes["FK_Posts_Authors"].FirstOrDefault();
var tags = row.Includes["Tags"];
}
// Insert, with hooks
var data = new DataCommandApi(dialect, registry);
data.BeforeCreate += (schema, table, values, ct) => { /* validate */ return Task.CompletedTask; };
var post = await data.CreateAsync(connection, "dbo", "Posts", new Dictionary<string, object?>
{
["Title"] = "Hello, SequelizeDotNet",
["AuthorId"] = 42,
});
// Bulk insert
var created = await data.CreateManyAsync(connection, "dbo", "Tags",
[
new Dictionary<string, object?> { ["Name"] = "dotnet" },
new Dictionary<string, object?> { ["Name"] = "orm" },
]);
// Explicit, named DDL — never automatic
var schemaApi = new SchemaCommandApi(dialect, registry);
await schemaApi.AddColumnAsync(connection, "dbo", "Posts",
new ColumnDefinition("ViewCount", ColumnDataType.Integer, IsNullable: false));
Full runnable examples — transactions, schema drift/hot-reload, CDC watching, code generation — are in the Developer Guide.
CLI reference
sequelizedotnet db:pull <connectionString> [--dialect D]
sequelizedotnet snapshot <connectionString> <outputJsonPath> [--dialect D]
sequelizedotnet diff <connectionString> <previousSnapshotJsonPath> [--dialect D]
sequelizedotnet codegen <connectionString> <namespace> <outputDirectory> [--dialect D]
sequelizedotnet codegen-openapi <connectionString> <outputJsonPath> [--title T] [--api-version V] [--dialect D]
sequelizedotnet codegen-graphql <connectionString> <outputGraphQlPath> [--dialect D]
sequelizedotnet schema add-column|drop-column|rename-column|rename-table|change-column-type|drop-table ...
sequelizedotnet data insert|bulk-insert|update|delete ...
sequelizedotnet watch <connectionString> [--interval-seconds N] [--dialect D]
sequelizedotnet watch-cdc <connectionString> <captureInstance> [--interval-seconds N]
--dialect accepts sqlserver (default), postgres, sqlite, mysql, oracle, db2. Run sequelizedotnet --help for the full, current usage text — it's the source of truth, generated from the same code this README describes.
Documentation
The Developer Guide covers everything in depth: full API walkthroughs for every feature above, transaction patterns, hook ordering guarantees, the exact SQL each dialect generates for bulk insert, how schema hot-reload interacts with in-flight queries, and troubleshooting notes (including the SQL Server Express/CDC limitation in full). The full architectural decision log — including options considered and rejected — lives in docs/PLAN.md (Persian).
Roadmap / known limitations
Deliberately out of scope for this release (tracked in docs/PLAN.md §8):
- Live end-to-end testing of PostgreSQL, MySQL, Oracle, and DB2 (implemented, unit-tested only — see testing status)
- Live end-to-end CDC testing (needs a non-Express SQL Server instance)
CHANGELOG.mdand XML doc comments for consumer-side IntelliSense- A full CI pipeline running the test suite on every push (the NuGet publish workflow exists; a build/test-on-PR workflow does not, yet)
Contributing
Contributions are very welcome — this project explicitly wants outside eyes, especially on the four unit-tested-only dialects and on real-world Sequelize migration stories. See CONTRIBUTING.md for how to get started, the project's testing conventions, and what kinds of PRs are most valuable right now (hint: a Postgres/MySQL/Oracle/DB2 instance you can point live tests at is the single most useful thing you can contribute).
Bug reports, design pushback, and "here's how Sequelize handles this edge case" comments are just as valuable as code — please open an issue.
Acknowledgments
This project would not exist without Sequelize.js (GitHub) and the ideas it spent over a decade refining — associations, hooks, a query layer that respects SQL instead of hiding it, and a database-first mental model that most ORMs in most ecosystems still don't offer as a first-class citizen. Thank you to everyone who has ever contributed to it.
Also drawing on prior art and public discussion around: EF Core's dynamic model support, runtime EF Core models, database schema diffing tools like Atlas and DBDiff, and the OpenSSF Trusted Publishers initiative that this project's own release pipeline uses via NuGet Trusted Publishing.
License
MIT — use it, fork it, ship it.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Net.IBM.Data.Db2 (>= 10.0.0.200)
- SequelizeDotNet.Abstractions (>= 0.1.0)
- SQLitePCLRaw.lib.e_sqlite3 (>= 3.53.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 120 | 7/31/2026 |