Introducing RepoDb.Connector.MariaDb - RepoDB’s de-facto connector for MariaDB in .NET
Published:
We just announced RepoDB Connectors, a new home for dedicated, provider-specific ADO.NET data providers built for RepoDB — read the announcement at Introducing RepoDB Connectors — Starting with MariaDB if you haven’t yet. This post goes one level deeper into the first connector that shipped out of it, RepoDb.Connector.MariaDb: why it exists, how it’s laid out internally, the objects it exposes, and enough code to get productive with it right away.
Status: Early development. The API and implementation are subject to change. Disclaimer: This is an independent, unofficial .NET provider for MariaDB. It is a thin ADO.NET wrapper and type-mapping layer built on top of MySql.Data and is not affiliated with or endorsed by MariaDB plc or the MariaDB Foundation.
Why does MariaDb need its own connector?
MySQL and MariaDb are close relatives, but they aren’t the same server, and RepoDB already ships dedicated extensions for both — RepoDb.MySql, RepoDb.MySqlConnector, and now RepoDb.MariaDb. Once you have three extensions in play, you need a way to introduce MariaDb-specific ADO.NET objects — connections, commands, parameters, types — without those objects colliding with the ones already registered for MySQL.
RepoDb.Connector.MariaDb is that answer: every public type is prefixed with MariaDb, so MariaDbConnection can live in the same process as MySqlConnection without ambiguity, while both ultimately still talk to the server through Oracle’s MySql.Data driver under the hood. It’s the same idea RepoDB already applies to SQL Server, PostgreSQL, and Oracle — a dedicated, standardized System.Data.Common surface per provider — now extended to MariaDb, and it’s what powers RepoDb.MariaDb and RepoDb.MariaDb.BulkOperations internally.
Architecture
RepoDb.Connector.MariaDb is more than a set of wrapper classes sitting in front of MySql.Data. Conceptually, the public ADO.NET API sits on top of the MariaDB communication and protocol infrastructure — authentication, TLS negotiation, prepared statement handling, parameter encoding, result set parsing, type encoding/decoding, and cancellation — which in turn talks the MariaDB wire protocol over TCP to the server:
Application / ORM
│
▼
MariaDbConnection
│
▼
MariaDbCommand
│
▼
MariaDB Session
│
├── Authentication
├── TLS
├── Prepared Statements
├── Parameter Encoding
├── Result Set Parsing
├── Type Encoding/Decoding
└── Cancellation
│
▼
MariaDB Protocol
│
▼
TCP
│
▼
MariaDB Server
Because everything is expressed against System.Data.Common base classes, the connector composes naturally with anything that already speaks ADO.NET — RepoDB, Dapper, hand-rolled data access layers, or raw DbConnection/DbCommand code:
RepoDB
Dapper
Custom Data Access Layers
ADO.NET Applications
Other DbConnection-based Libraries
│
▼
RepoDb.Connector.MariaDb
│
▼
MariaDB Server
The connector itself stays independent of any ORM — RepoDB is simply the first (and primary) consumer.
The objects
The core of the connector is a standard ADO.NET provider implementation — one MariaDb-prefixed type per System.Data.Common abstraction:
| RepoDb.Connector.MariaDb | ADO.NET Base Class | Purpose |
|---|---|---|
MariaDbConnection | DbConnection | Establishes and manages MariaDB connections |
MariaDbCommand | DbCommand | Executes SQL commands |
MariaDbDataReader | DbDataReader | Reads query results |
MariaDbParameter | DbParameter | Represents command parameters |
MariaDbParameterCollection | DbParameterCollection | Manages command parameters |
MariaDbTransaction | DbTransaction | Manages database transactions |
MariaDbException | DbException | Represents MariaDB errors |
MariaDbConnectionStringBuilder | DbConnectionStringBuilder | Builds and parses connection strings |
MariaDbProviderFactory | DbProviderFactory | Creates provider-specific ADO.NET objects |
Bulk-loading lives in its own namespace, RepoDb.Connector.MariaDb.Bulk, built on top of LOAD DATA LOCAL INFILE via MySql.Data’s MySqlBulkLoader:
| RepoDb.Connector.MariaDb.Bulk | Purpose |
|---|---|
MariaDbBulkCopy | Efficiently bulk-loads a DbDataReader/IDataReader, DataTable, or DataRow[] into a table |
MariaDbBulkColumnMapping | Defines the mapping between a source column and a destination column |
MariaDbBulkCopyColumnMappingCollection | The collection of MariaDbBulkColumnMapping objects exposed by MariaDbBulkCopy.ColumnMappings |
MariaDbBulkLoader | A strongly typed wrapper around LOAD DATA LOCAL INFILE, for loading from a file or stream |
MariaDbBulkLoaderConflictOption | Controls behavior when a key conflict arises during a load |
MariaDbBulkLoaderPriority | Controls the priority (None, Low, Concurrent) of a bulk load operation |
Basic usage
At its simplest, RepoDb.Connector.MariaDb gives you the ordinary ADO.NET programming model, just with MariaDb-prefixed types:
using RepoDb.Connector.MariaDb;
var connectionString =
"Server=localhost;" +
"Port=3306;" +
"Database=TestDb;" +
"User ID=root;" +
"Password=password;";
await using var connection =
new MariaDbConnection(connectionString);
await connection.OpenAsync();
await using var command = connection.CreateCommand();
command.CommandText = """
SELECT Id, Name, Email
FROM Customer
WHERE Id = @Id;
""";
command.Parameters.AddWithValue("@Id", 100);
await using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
var id = reader.GetInt32(0);
var name = reader.GetString(1);
var email = reader.GetString(2);
Console.WriteLine($"{id}: {name} ({email})");
}
MariaDbConnection
MariaDbConnection extends DbConnection and owns connection establishment, state, session management, command/transaction creation, and connection string handling — synchronously and asynchronously:
await using var connection =
new MariaDbConnection(connectionString);
await connection.OpenAsync();
Console.WriteLine(connection.ServerVersion);
Console.WriteLine(connection.Database);
Console.WriteLine(connection.State);
MariaDbCommand
MariaDbCommand extends DbCommand and represents a SQL statement executed against MariaDB — parameterized SQL, prepared statements, command timeout, cancellation, and multiple result sets are all part of the target surface:
await using var command = new MariaDbCommand(
"SELECT * FROM Customer WHERE Id = @Id",
connection);
command.Parameters.AddWithValue("@Id", 100);
await using var reader =
await command.ExecuteReaderAsync();
MariaDbParameter and MariaDbType
MariaDbParameter extends DbParameter and represents a single parameter on a MariaDbCommand:
var parameter = new MariaDbParameter
{
ParameterName = "@Id",
Value = 100
};
command.Parameters.Add(parameter);
Alongside the standard DbType, the connector introduces a MariaDbType enumeration for MariaDB-specific data type mapping — covering numeric types (TinyInt through BigInt, Decimal, Float, Double, Bit), text types (Char through LongText, Enum, Set), binary types (Binary through LongBlob), temporal types (Date, Time, DateTime, Timestamp, Year), Json, and the full spatial family (Geometry, Point, LineString, Polygon, and their Multi*/GeometryCollection counterparts):
var parameter = new MariaDbParameter
{
ParameterName = "@Id",
MariaDbType = MariaDbType.Int,
Value = 100
};
The mapping chain runs both directions — MariaDbType ↔ DbType ↔ .NET CLR type ↔ MariaDB server type — and MariaDbTypeConverter currently covers the leg between MariaDbType and MySql.Data.MySqlClient.MySqlDbType:
var mariaDbType = MariaDbTypeConverter.ToMariaDbType(MySqlDbType.VarChar);
var mySqlDbType = MariaDbTypeConverter.ToMySqlDbType(MariaDbType.BigInt);
Transactions
MariaDbTransaction extends DbTransaction and provides the usual ADO.NET transaction semantics — begin, commit, rollback, sync and async:
await using var transaction =
await connection.BeginTransactionAsync();
try
{
await using var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText =
"UPDATE Customer SET Name = @Name WHERE Id = @Id";
command.Parameters.AddWithValue("@Name", "John Doe");
command.Parameters.AddWithValue("@Id", 100);
await command.ExecuteNonQueryAsync();
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
Connection string builder
MariaDbConnectionStringBuilder extends DbConnectionStringBuilder, giving you a strongly typed way to assemble connection strings instead of hand-concatenating them:
var builder = new MariaDbConnectionStringBuilder
{
Server = "localhost",
Port = 3306,
Database = "TestDb",
UserId = "root",
Password = "password"
};
await using var connection =
new MariaDbConnection(builder.ConnectionString);
await connection.OpenAsync();
Provider factory
MariaDbProviderFactory extends DbProviderFactory, letting provider-independent ADO.NET code create RepoDb.Connector.MariaDb objects without a hard compile-time reference to the concrete types:
var factory = MariaDbProviderFactory.Instance;
using var connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
connection.Open();
Bulk operations
Row-by-row INSERT statements cost a round-trip each. When you’re moving thousands or millions of rows — an import, a migration, a catch-up sync — that overhead adds up. RepoDb.Connector.MariaDb.Bulk addresses that by wrapping MariaDB’s LOAD DATA LOCAL INFILE mechanism, exposed through Oracle’s MySql.Data-provided MySqlBulkLoader.
MariaDbBulkCopy
MariaDbBulkCopy writes its source rows to a temporary file and loads them through MariaDbBulkLoader. It accepts an IDataReader, a DbDataReader, a DataTable (optionally filtered by DataRowState), or a DataRow[]:
await using var connection =
new MariaDbConnection(connectionString);
await connection.OpenAsync();
using var bulkCopy = new MariaDbBulkCopy(connection)
{
DestinationTableName = "Customer",
BatchSize = 10_000
};
bulkCopy.ColumnMappings.Add("Id", "Id");
bulkCopy.ColumnMappings.Add("Name", "Name");
bulkCopy.ColumnMappings.Add("Email", "Email");
await bulkCopy.WriteToServerAsync(customersDataTable);
Console.WriteLine(bulkCopy.RowsCopied);
MariaDbBulkLoader
If you already have a file or stream on disk, MariaDbBulkLoader can be used directly, without going through MariaDbBulkCopy:
var bulkLoader = new MariaDbBulkLoader(connection)
{
TableName = "Customer",
FileName = "customers.csv",
FieldTerminator = ",",
LineTerminator = "\n",
Local = true
};
bulkLoader.Columns.Add("Id");
bulkLoader.Columns.Add("Name");
bulkLoader.Columns.Add("Email");
var rowsLoaded = await bulkLoader.LoadAsync();
MariaDbBulkLoaderConflictOption controls how a load reacts to key conflicts, and MariaDbBulkLoaderPriority (None, Low, Concurrent) controls how the load is scheduled relative to other server activity.
Where this fits with RepoDB
If you’re already using RepoDb.MariaDb for fluent CRUD or RepoDb.MariaDb.BulkOperations for BulkInsert/BulkUpdate/BulkMerge/BulkDelete, you’re already exercising this connector — every MariaDbConnection those extensions create underneath is the exact type covered in this post. You don’t need to change anything to benefit from it; it’s the layer that makes RepoDB’s provider-agnostic API work correctly against MariaDB specifically, without colliding with the MySQL-flavored objects RepoDB already registers.
You can also use it directly, with no ORM at all, or hand it to any other library that only expects a DbConnection — Dapper included.
What’s next
The initial development effort prioritizes the core connection, command, parameter, transaction, and data-reader infrastructure. Beyond that, the roadmap includes connection pooling, richer prepared-statement support, TLS/SSL, additional authentication mechanisms, cancellation, multiple result sets, advanced server metadata, MariaDbDataAdapter, MariaDbCommandBuilder, and eventually a native (non LOAD DATA-based) bulk execution protocol.
As a preview, expect the API surface to keep moving. If you run into a rough edge — or want to help build out the MariaDB wire protocol implementation, authentication, or type mappings — contributions are very welcome.
- GitHub: RepoDB.Connectors
- NuGet: RepoDb.Connector.MariaDb
- Announcement: Introducing RepoDB Connectors — Starting with MariaDB
Please support us
Give a ⭐ to our Github repository | Follow me at X / Twitter | Connect with us at our official Teams Channel
Apache License 2.0 — Copyright © 2026 by Michael Camara Pendon / Create a Request
