Class Hierarchy

IRDBSource

Framework interface defining the RDBMS contract: CRUD, schema loading, query execution, DDL generation, and transaction management.

RDBSource

Main implementation — a partial class split across 16 files organized by responsibility. ~5,400 lines total. Database-agnostic via ADO.NET abstraction.

InMemoryRDBSource

Extends RDBSource with IInMemoryDB. Adds ETL-based data sync, lifecycle management (IsCreated, IsLoaded, IsSynced), and structure creation.

RDBDataConnection

Wraps IDbConnection. Handles driver instantiation via DMEEditor.assemblyHandler, connection string building, schema alteration.

Partial Class Breakdown (16 Files)

FileLinesResponsibility
RDBSource.cs164Core properties, constructor, EntityStructureCache, events
RDBSource.Connection.cs33Open/close delegation to RDBDataConnection
RDBSource.Transaction.cs66Begin/End/Commit transaction (⚠️ Commit stub)
RDBSource.CRUD.cs585InsertEntity, UpdateEntity, DeleteEntity + async variants
RDBSource.Query.cs1,004GetEntity, RunQuery, ExecuteSql, BuildQuery, SQL parsing
RDBSource.DMLGeneration.cs911INSERT/UPDATE/DELETE SQL generation, DDL, parameter creation
RDBSource.Schema.cs830Entity structure loading, FK detection, Oracle FLOAT mapping
RDBSource.BulkOperations.cs1,080Bulk insert/update, temp-table strategies, multi-row optimization
RDBSource.Cache.cs252Query cache, result cache (MemoryCache), prepared statements
RDBSource.Modernization.cs497IAsyncEnumerable streaming, async paging, scalar/non-query
RDBSource.Resilience.cs426Polly v8 retry + circuit breaker, health checks
RDBSource.Dapper.cs38Dapper Query<T> + ExecuteAsync<T> wrappers
RDBSource.TypeMapping.cs108DbType conversion + value conversion (all .NET types)
RDBSource.Utilities.cs297Error handling, GetDataCommand, GetDataAdapter, naming
RDBSource.Pagination.cs12⚠️ Empty stub — paging logic lives in Modernization.cs
RDBSource.Dispose.cs45IDisposable pattern, connection cleanup

Helper Classes

ClassLinesPurpose
DataStreamer109Streams IDataReader → Dictionary<string,object> or typed objects with cached property mapping
DbTypeMapper38Static dictionary mapping .NET type strings → DbType
EntityStructureCache27Thread-safe ConcurrentDictionary with refresh-on-demand loader
PagedQueryExecutor118Builds count query + paged query, executes both, returns (rows, total)
PaginationHelper15Delegates to RDBMSHelper.GetPagingSyntax for DB-specific paging

Key Design Patterns

Provider Abstraction

Database drivers are loaded dynamically via DMEEditor.assemblyHandler.GetInstance(typeName). The plugin has no compile-time dependency on any specific ADO.NET provider. Supported engines:

EnginePaging SyntaxTemp TablesHealth Check
SQL ServerOFFSET/FETCH#tempSELECT 1
MySQLLIMIT/OFFSETCREATE TEMPORARY TABLESELECT 1
PostgreSQLLIMIT/OFFSETCREATE TEMP TABLESELECT 1
OracleROWNUM subquery—SELECT 1 FROM DUAL
SQLiteLIMIT/OFFSET—SELECT 1
DB2——SELECT 1 FROM SYSIBM.SYSDUMMY1

Resilience Pipeline

Polly v8 ResiliencePipeline combines circuit breaker (50% failure ratio, 30s duration) + retry (exponential backoff, 3 attempts). Health checks issue database-specific ping queries and auto-reopen connections.

Multi-Level Caching

  • Query cache — ConcurrentDictionary<string,string> for compiled query strings
  • Result cache — MemoryCache with configurable TTL (default 5 min, size limit 1024 entries)
  • Prepared statement cache — ConcurrentDictionary for command text reuse
  • Entity structure cache — EntityStructureCache (ConcurrentDictionary with refresh)
  • Property mapping cache — DataStreamer caches reflected property info per type

Bulk Operation Strategies

  • Multi-row INSERT — INSERT INTO t VALUES (...), (...), (...) for SQL Server/MySQL/PostgreSQL/SQLite
  • Temp-table MERGE — Create temp table → bulk insert → MERGE/UPDATE JOIN for SQL Server/MySQL/PostgreSQL
  • Batched fallback — Individual INSERT/UPDATE wrapped in transaction for Oracle/DB2

Known Issues

The authoritative defect register lives with the code, at DataSourcesPlugins/RDBMSDataSource/docs/10-known-issues.md, where every entry carries a reproducing scenario and a fix direction. The table below is a severity summary only.

SeverityIssueLocation
🔴 CriticalA null Logger makes AddLogMessage return before setting the error flag, so ~40 failure paths report success — including a CREATE TABLE that never ranBeepDM DMEEditor.cs:204
🔴 CriticalUPDATE primary-key parameters are resolved by substring, so an UPDATE can target a row chosen by the wrong column's valueDMLGeneration.cs:304
🔴 CriticalZero rows affected is logged as a failure but returned as success; bulk success counters inherit thisCRUD.cs:74
🔴 CriticalGetFieldName emits a string literal rather than a quoted identifier on every driver but SQLite; reserved-word columns are never quoted at allUtilities.cs:272
🔴 CriticalSQL injection through AppFilter.Operator and FieldName — filter values are parameterised, these are notBeepDM DataSourceAppFilterExtensions.cs
🔴 CriticalBulk insert reflects on typeof(T), so IEnumerable<object> input writes an all-NULL table and reports successBulkOperations.cs:763
🔴 CriticalEvery SQL Server connection runs ALTER LOGIN … DEFAULT_DATABASE, a permanent server-wide change to the loginRDBDataConnection.cs:180
🟠 HighHana, Snowflake and Presto set ParameterDelimiter = "?", so their write path cannot bind at alldriver constructors
🟠 HighBulk batches open a transaction the row commands never join — Oracle bulk insert fails by defaultBulkOperations.cs:312
🟠 HighTemp-table DDL emits .NET type names as SQL types, so bulk update fails on SQL Server, MySQL and PostgreSQLBulkOperations.cs:950
🟠 HighSchema and table concatenated with no . separator at six sites, breaking bulk and the async/paged read pathsBulkOperations.cs, Modernization.cs
🟠 HighTwo paging implementations with opposite defaults; AzureSQL and SqlCompact produce a syntax error on every paged readQuery.cs:797, Modernization.cs:412
🟠 HighGetTableName rewrites SQL by string surgery; an entity named updates throws IndexOutOfRangeExceptionUtilities.cs:291
🟡 MediumThe Polly resilience layer is wired to no query path, and would not fire anyway because OpenConn swallows exceptions internallyResilience.cs
🟡 MediumMost of Cache.cs has no callers yet logs “Cache invalidated” on every write; EntityStructureCache, the live one, has no invalidation at allCache.cs, EntityStructureCache.cs
🟡 MediumPer-operation state is held in shared instance fields; the “thread-safe per-operation” comment is invertedRDBSource.cs:32
🟡 MediumDispose nulls its collections and releases neither the active transaction, the retained command, nor the connectionDispose.cs

Previously listed here and since fixed: UpdateEntities() calling InsertEntity(); Commit() and EndTransaction() as empty stubs (commit c3901629); the MemoryCache key-enumeration gap.

Developer reference

A per-file walkthrough of all sixteen partial classes lives alongside the source, at DataSourcesPlugins/RDBMSDataSource/docs/.

DocumentCovers
README.mdFile map, the fourteen drivers, what a driver actually overrides
01-error-model.mdHow success and failure are reported — read first
02-lifecycle.mdConstruction, connection, shared state, disposal
03-transactions.md_activeTransaction, and why EndTransaction means rollback
04-crud-dml.mdThe write path, parameter binding, DDL generation
05-query-paging.mdThe read path and its four paging routes
06-schema-types.mdStructure discovery, entity types, type mapping
07-bulk.mdBatching, temp tables, transaction scope
08-cache-resilience.mdWhat is live, and what is built but not wired up
09-extending.mdWriting a driver: what to override, what to avoid
10-known-issues.mdThe defect register with reproducing scenarios