EntitySpaces.ORM.MySQL.NET
2026.11.0
dotnet add package EntitySpaces.ORM.MySQL.NET --version 2026.11.0
NuGet\Install-Package EntitySpaces.ORM.MySQL.NET -Version 2026.11.0
<PackageReference Include="EntitySpaces.ORM.MySQL.NET" Version="2026.11.0" />
<PackageVersion Include="EntitySpaces.ORM.MySQL.NET" Version="2026.11.0" />
<PackageReference Include="EntitySpaces.ORM.MySQL.NET" />
paket add EntitySpaces.ORM.MySQL.NET --version 2026.11.0
#r "nuget: EntitySpaces.ORM.MySQL.NET, 2026.11.0"
#:package EntitySpaces.ORM.MySQL.NET@2026.11.0
#addin nuget:?package=EntitySpaces.ORM.MySQL.NET&version=2026.11.0
#tool nuget:?package=EntitySpaces.ORM.MySQL.NET&version=2026.11.0
<img src="https://es-banner.paul-netstep.workers.dev?src=nuget_readme" alt="EntitySpaces" width="250" height="126">
EntitySpaces.ORM.MySQL.NET
Part of the modernized EntitySpaces ORM β MySQL / MariaDB data provider. Actively maintained fork with full .NET Framework 4.8 to .NET 10 support.
Supportability
| .NET targets | .NET Framework 4.8 - .NET 8 - .NET 9 - .NET 10 |
| MySQL / MariaDB | MySQL 8.0.14+ (validated with 8.0.28) - MariaDB 10.2+ (validated with 10.2 / 10.6 / 10.11) |
| Driver | MySqlConnector 2.6.2 |
π οΈ Requires EntitySpaces Studio
This package provides the MySQL / MariaDB runtime only β it does not generate code. Entity and Collection classes are generated from your database schema using EntitySpaces Studio, a separate WinForms tool.
- Download the latest MSI from Releases and run it. Requires the .NET 10 Desktop Runtime (x64).
- Older builds stay in EntitySpaces.Studio, tagged
-deprecated, for reference only.
Version alignment. Studio 2026.11 and the NuGet packages 2026.11.0 ship as one unit: the templates depend on provider changes from the same release. Do not mix a newer Studio with older packages, or the reverse. The previous Studio build (2026.08) remains available for projects still on packages 2026.8.0.
- Connect to your database under Settings β Connection, then run the Generated and Custom class templates.
- If you plan to use the Stored Procedure save path (
esSqlAccessType.StoredProcedure), configure the Custom Fields tabs before generating the procedures. The names entered there must match the physical column names in your database β see the Stored Procedure Support section below for the full setup checklist.
New Features
Stored Procedure generation with optimistic concurrency β the generated
Insert/Update/Deleteprocedures carry the same concurrency contract as the dynamic SQL path:Insert takes
pVersionas anOUTparameter, excludesdateAdded/dateModified/versionfrom theINSERTcolumn list (the DDLDEFAULTfills them), and returns the generated values back to the entity viaSELECT ... INTOafterLAST_INSERT_ID().Update declares
pDateAdded/pDateModified/pVersionasINOUT, bumpsversionserver-side withSET version = version + 1, refreshesdateModifiedwithCURRENT_TIMESTAMP(6), and addsAND version = pVersionto theWHEREclause. When zero rows match, the procedure raisesSIGNAL SQLSTATE '45000'so the application receives anesConcurrencyExceptioninstead of a silent no-op.Delete accepts
pVersionand appends it to theWHEREclause, with the same concurrency signal on zero rows.
The generated scripts are also free of
USEstatements β the schema is resolved at deployment time by the target (CLI-D, Workbench active schema, migration tool connection string) rather than hardcoded at generation time.Tolerant column/property name resolution β the provider accepts both the database column name and the generated property name when deciding whether a column is part of an INSERT/UPDATE/DELETE and when mapping server-returned values back to the entity. This covers:
- Lowercase column names (
invoiceidcolumn βInvoiceidproperty) β the common MySQL/MariaDB convention in Northwind-derived schemas. - Arbitrary divergence between a FK column and the PK column it references, without splitting on an underscore.
- No code changes required; the tolerant resolution is applied uniformly to INSERT, UPDATE, DELETE, and server-returned value mapping.
- Lowercase column names (
Server-side key sync after INSERT/UPDATE β after a successful INSERT or UPDATE, the provider synchronizes both keys (column name
invoiceidand property nameInvoiceid) in the entity'sCurrentValues, so the in-memory getter sees the value that was persisted. This is what makes hierarchical saves and explicit-PK inserts return the expected value from the FK getter.Explicit
AUTO_INCREMENTPK insert β when a user assigns a value to an auto-increment PK, the column is sent as an input parameter and included in the INSERT; MySQL uses the explicit value instead of generating a new one. Combined with the key sync, the entity is marked clean after save and the value is preserved.Automatic engine detection β the provider queries
SELECT VERSION()on the first call per connection string and caches the result. No configuration required to distinguish MySQL from MariaDB.Automatic
APPLYβ correct SQL strategy per engine β writeOuterApply/CrossApplyonce; the provider emits nativeLEFT JOIN LATERAL/JOIN LATERALon MySQL 8.0.14+, and an equivalentROW_NUMBER() OVER (PARTITION BY)pattern on MariaDB 10.2+ and older MySQL.Concurrency exception detection and translation to
esConcurrencyExceptionβ duplicate entry, deadlock, and lock-wait timeout are translated to the same exception type used by every other EntitySpaces provider.Removed explicit
ROLLBACKfrom error paths β the provider no longer issuesROLLBACKon enlisted connections. On anesTransactionScope-enlisted connection,ROLLBACKaborts the ambient transaction, not just the current command. Rollback is now delegated entirely toesTransactionScope, which is the correct owner and matches the pattern already applied to the PostgreSQL provider.OnRowUpdatedno longer swallows exceptions β exceptions during server-side value retrieval (LAST_INSERT_ID(),LastTimestamp(), defaults) are now surfaced viaDebug.WriteLineandTrace.WriteLine. Previously acatch { }block silently hid failures during post-insert processing.AutoInc and Defaults values written to both key names (
idandId) β the entity getter and the provider now see the same value after an INSERT with server-generated columns.Thread-safe parameter cache β the parameter cache is a
ConcurrentDictionarykeyed byDataID. No lock contention in multi-threaded environments; the cache is built once per entity type and reused safely across threads.Studio metadata engine now extracts the
EXTRAcolumn (VIRTUAL GENERATED/STORED GENERATED) for computed-column detection andTIMESTAMPconcurrency detection. See the main README's Studio Modernization section for the full metadata matrix (character max length, numeric precision/scale, computed columns, auto-increment, defaults).
Fixes
Hierarchical parent-child save with lowercase column names β children were inserted with a NULL foreign key on schemas where the FK column uses a lowercase convention (
invoiceidcolumn vsInvoiceidproperty). The INSERT builder now resolves the FK column by either name and includes it in the statement. Combined with the server-side key sync, both the persisted value and the in-memory getter reflect the propagated parent PK:Parent.Id = 22 (parent inserted) Child.Id = 9 (child inserted) Child.Invoiceid = 22 (FK correctly propagated) Child.IsDirty = False (framework cleared the entity)Corrected parameter lookup in
OnRowUpdatedβ the parameter name for the auto-increment value is?PropertyName, not?ColumnName. The old code constructed"?" + columnNameand silently failed to find the parameter; the fix iterates bySourceColumn(which is the DB column name) to locate the correct parameter.Connection pool safety on error β all save and load operations release connections safely:
ExecuteReaderopens its own raw connection and closes it viaCleanupCommandwhenExecuteReader()itself fails βCommandBehavior.CloseConnectiononly fires whenExecuteReader()succeeds and the reader is disposed.- Other operations use
esTransactionScope.DeEnlist()infinallyblocks. - No explicit
ROLLBACKis issued β that responsibility belongs to the transaction scope owner.
This eliminates the class of bugs where an error in a child insert would abort an ambient transaction, not just the current command.
Documented and handled MySQL 8.0's
caching_sha2_passworddefault β MySQL 8.0 withcaching_sha2_passwordrequires eitherSslMode=RequiredorSslMode=Nonecombined withAllowPublicKeyRetrieval=True. Connections without this previously failed against default MySQL 8.0 configurations with an authentication error. See the connection string section below.Clarified case-sensitivity handling across platforms β MySQL on Linux is case-sensitive for table/schema names (
lower_case_table_names=0); MySQL on Windows and all MariaDB platforms are case-insensitive. Class generation is now documented to always run against the target server to guarantee consistent metadata. See the case-sensitivity section below.
β οΈ Transaction Management
Use esTransactionScope for transactions β not System.Transactions.TransactionScope.
MySqlConnector, like modern Npgsql and Microsoft.Data.SqlClient, does not enlist connections into ambient System.Transactions.TransactionScope transactions automatically. If your application relies on TransactionScope for rollback, the INSERT/UPDATE will run in autocommit mode and the rollback will not revert your data.
The provider participates correctly in EntitySpaces' native esTransactionScope, which is the supported mechanism across all EntitySpaces providers:
using (var scope = new esTransactionScope())
{
var employee = new Employee { FirstName = "Joe", LastName = "Smith" };
employee.Save();
var product = new Product { ProductName = "Some Gadget" };
product.Save();
scope.Complete(); // commit; omit to roll back
}
Nested esTransactionScope instances are supported β the inner scope votes on the outer transaction. Omitting Complete() on any scope that owns the root transaction rolls back everything created inside it.
AutoEnlistconnection string setting is irrelevant foresTransactionScope. It only affectsSystem.Transactionsenlistment and can be left at either value.
Connection pool behavior on error: All save and load operations release connections safely. On error, the connection is closed by
CleanupCommand(or byCommandBehavior.CloseConnectionwhen a reader was opened). No explicitROLLBACKis issued β that responsibility belongs to the transaction scope owner. This matches the pattern applied across the PostgreSQL provider and avoids the class of bugs where a child insert failure would abort an otherwise recoverable transaction.
The same rules apply to the Stored Procedure save path. Concurrency signals raised inside a procedure (
SIGNAL SQLSTATE '45000') surface asesConcurrencyExceptionand participate in the ambientesTransactionScopeexactly like a dynamic-SQL concurrency failure.
Note: the previous implementation issued
ROLLBACKon enlisted connections insidefinallyblocks. UnderMySqlConnector/ ambientesTransactionScope, that aborted the ambient transaction, not just the current command. This was actively harmful and is no longer done.
β οΈ Hierarchical Save
Hierarchical parent-child saves work correctly on MySQL and MariaDB when using the pattern that EntitySpaces was designed for β adding the child to the parent's collection before calling parent.Save():
var order = new Salesorder
{
CustId = 65,
ShipperId = 3,
EmployeeId = 1,
OrderDate = DateTime.Now
};
// Recommended β add to the parent's collection
order.OrderdetailCollectionByOrderId.Add(new Orderdetail
{
ProductId = 1,
UnitPrice = 15.50m,
Quantity = 5,
Discount = 0m
});
order.Save(); // saves the parent first, then each child with the correct FK
AddNew() works the same way:
var detail = order.OrderdetailCollectionByOrderId.AddNew();
detail.ProductId = 2;
detail.UnitPrice = 10.00m;
detail.Quantity = 2;
detail.Discount = 0m;
order.Save();
The child-initiated pattern (save from the child with UpTo set) is also supported:
var detail = new Orderdetail { ProductId = 1, UnitPrice = 25m, Quantity = 3, Discount = 0m };
detail.UpToSalesorderByOrderId = order;
detail.Save(); // saves the parent first to obtain the PK, then the child
Atomicity β implicit transaction
esEntity.Save() automatically wraps hierarchical saves in an esTransactionScope when the entity has any pre-saves, post-saves, or post-one-saves (i.e. NeedsTransactionDuringSave() returns true). On any exception during the save phases, the scope is rolled back β the parent insert is reverted along with the failed child. No explicit esTransactionScope is required for the common hierarchical case.
For single-entity saves without hierarchy, no scope is created; the operation is a single SQL statement and therefore inherently atomic.
An explicit esTransactionScope around a hierarchical save is optional but recommended when multiple independent entities must succeed or fail together β the framework's internal scope joins the ambient one transparently via Required semantics.
Non-identity parent PKs
FK propagation from parent to child works identically for auto-increment PKs and user-supplied PKs:
- Auto-increment parent β
Salesorder.OrderId(AUTO_INCREMENT): the parent is inserted, the generated value is retrieved viaLAST_INSERT_ID(), and the FK is written into the child before the child's INSERT. - User-supplied parent β
Region.RegionId(INT NOT NULL, noAUTO_INCREMENT): the parent PK is already known before the INSERT, so the FK is available immediately and the parent-child ordering is still preserved for referential integrity. - Explicit value on
AUTO_INCREMENTparent βSalesorder.OrderIdassigned explicitly by the application: MySQL accepts the explicit value; the provider routes it as an input parameter and the FK is propagated the same way.
All three paths are exercised by the test suite against MySQL 8 and MariaDB 10.11, covering all six save patterns: persist-then-add, save-together, AddNew(), child-initiated via UpTo, collection-initiated via collection.Save(), and collection.BulkInsert().
β οΈ Do not use bidirectional linking. Setting both
parent.Children.Add(child)andchild.UpToParent = parentcauses infinite recursion between the parent and child navigation properties. In practice this manifests as a hang or aStackOverflowExceptiondepending on the runtime. This is a limitation of the current EntitySpaces Core, not of this provider. Use one direction β the collection when saving from the parent, orUpTowhen saving from the child.
Collection Combine()
esEntityCollection<T>.Combine(source) moves entities from a source collection into a target collection. When the target has fks populated by a parent navigation getter (e.g. Customer.SalesorderCollectionByCustId), the FK values are written into each combined entity's CurrentValues and marked as modified so they are included in the subsequent INSERT. The operation preserves the RowState of Unchanged entities whose FK already matches, and does not duplicate the FK entry in ModifiedColumns.
var source = new SalesorderCollection();
var order = source.AddNew();
order.ShipperId = 3;
order.EmployeeId = 1;
order.OrderDate = DateTime.Now;
var target = customer.SalesorderCollectionByCustId;
target.Combine(source);
target.Save(); // FK is written and persisted
Cross-provider parity
The fixes documented in this README were originally validated against SQL Server, then ported to PostgreSQL, and now to MySQL/MariaDB without provider-specific changes. Stored Procedure generation with full concurrency support (Insert/Update/Delete) is also validated against MySQL 8.0.28 and MariaDB 10.11, and behaves identically to the SQL Server and Oracle procedures. The following behaviours are validated against MySQL 8.0.28 and MariaDB 10.11:
- Hierarchical save for auto-increment, user-supplied, and explicit-value PKs.
- FK propagation across all six save patterns (including
BulkInsert). - Tolerant column/property name resolution, including divergent FK names.
Combine()FK propagation andRowStatepreservation.- Transaction scope, rollback, and atomicity β including CHECK-constraint-triggered rollback of an in-flight hierarchy.
- Implicit transaction created by
esEntity.Save()on theNeedsTransactionDuringSave()path.
Stored Procedure Support
The provider ships with a Stored Procedure template for MySQL / MariaDB that generates the full CRUD surface (LoadByPrimaryKey, LoadAll, Insert, Update, Delete) with the same behavior the dynamic SQL path already provides β including optimistic concurrency and server-side special columns (dateAdded, dateModified, version).
What you get
- Full optimistic concurrency on
UpdateandDelete: a staleversionraisesesConcurrencyExceptioninstead of silently updating or deleting nothing. - Server-side timestamps:
dateAddedis set by the DDL default and never overwritten by the application.dateModifiedis refreshed on everyUpdate. versionhandling: initialized to1on insert, incremented server-side on every successful update.- Explicit PK inserts: assigning a value to an
AUTO_INCREMENTcolumn sends it as an input parameter; MySQL uses the explicit value and the entity is marked clean afterward.
Studio setup β Custom Fields
Before generating the Stored Procedures, configure the Custom Fields tab in EntitySpaces Studio so the generator recognizes the special columns. The names must match the physical column names in the database exactly, including case:
| Tab | Field | MySQL example |
|---|---|---|
| Dates β Date Added | Enable Date Added | dateAdded |
| Dates β Date Modified | Enable Date Modified | dateModified |
| UserID's β Added By | Enable Added By | addedBy |
| UserID's β Modified By | Enable Modified By | modifiedBy |
| Concurrency | Concurrency Column | version |
On Windows MySQL and all MariaDB platforms, casing is forgiving. On Linux MySQL (default lower_case_table_names=0), casing matters β DateAdded will not match a column defined as dateadded.
The concurrency column convention used by the shipped template is version (case-insensitive). If your schema uses a different name, either update the Custom Fields entry or extend the driver-level fallback (see the Provider Internals section of the main repository documentation).
Applying the generated script
The template emits a self-contained script (MySQL_ALL.sql) with the following properties:
- No
USEstatement. The script applies against whichever database the connection resolves at runtime:- CLI:
mysql -h host -u user -p -D mydb < MySQL_ALL.sql - Workbench: open the connection, set the active schema, execute the script
- Migration frameworks (Flyway, Liquibase, dbmate, etc.): pass the target DB in the connection string
- CLI:
DELIMITER //blocks. The script uses the alternate delimiter so that procedure bodies containing internal semicolons are parsed correctly by the client. If you execute the script through a driver API (MySqlCommand.ExecuteNonQuery()) rather than a MySQL client, split the script at each//boundary β the server itself does not recognizeDELIMITER(it is a client directive).
Save path selection
The provider selects between the two save strategies per call. Set it explicitly on the entity, the collection, or the connection:
// Per call
employee.Save(esSqlAccessType.StoredProcedure);
employee.Save(esSqlAccessType.DynamicSQL);
// Per collection
customers.es.Connection.SqlAccessType = esSqlAccessType.StoredProcedure;
customers.Save();
Both paths are fully supported and tested. The dynamic SQL path is the default for new connections; the SP path is typically chosen when database-side auditing, privilege restrictions, or query plan pinning call for stored procedures.
MySQL / MariaDB APPLY Support
EntitySpaces automatically translates OuterApply / CrossApply into the correct SQL strategy based on the detected server engine and version β no code changes required when switching between MySQL and MariaDB.
| EntitySpaces | MySQL 8.0.14+ | MariaDB 10.2+ |
|---|---|---|
OuterApply |
LEFT JOIN LATERAL |
LEFT JOIN + ROW_NUMBER() OVER (PARTITION BY) |
CrossApply |
JOIN LATERAL |
JOIN + ROW_NUMBER() OVER (PARTITION BY) |
Top(n) |
LIMIT n inside LATERAL |
es_rn <= n in outer ON clause |
Without Top() |
No LIMIT | All rows per partition returned |
Engine detection is automatic β the provider queries SELECT VERSION() on the first call per connection string and caches the result. No configuration required.
C# query (provider-agnostic):
var coll = new CustomerQuery("c", out var c)
.OuterApply<SalesorderQuery>(out var o, out var oCol, () =>
{
return (SalesorderQuery) new SalesorderQuery("o", out var subQuery)
.Select(subQuery.OrderId, subQuery.OrderDate)
.Top(2)
.Where(subQuery.CustId == c.CustId)
.OrderBy(subQuery.OrderDate.Descending);
})
.Select(c.CustId, c.CompanyName, oCol.OrderId)
.ToCollection<CustomerCollection>();
Generated SQL β MySQL 8.0.14+:
SELECT c.`custId`, c.`companyName`, o.`orderId`
FROM `customer` c
LEFT JOIN LATERAL (
SELECT o.`orderId`, o.`orderDate`
FROM `salesorder` o
WHERE o.`custId` = c.`custId`
ORDER BY o.`orderDate` DESC
LIMIT 2
) AS o ON TRUE
Generated SQL β MariaDB 10.2+:
SELECT c.`custId`, c.`companyName`, o.`orderId`
FROM `customer` c
LEFT JOIN (
SELECT o.`orderId`, o.`orderDate`, o.`custId`,
ROW_NUMBER() OVER (PARTITION BY o.`custId` ORDER BY o.`orderDate` DESC) AS es_rn
FROM `salesorder` o
) AS o ON o.`custId` = c.`custId`
AND o.es_rn <= 2
Concurrency Exception Detection
The provider translates MySQL and MariaDB-specific error codes into esConcurrencyException, consistent with all other EntitySpaces providers:
| Code | Condition | Translated To |
|---|---|---|
1062 |
Duplicate entry β PK or unique key violation | esConcurrencyException |
1205 |
Lock wait timeout exceeded | esConcurrencyException |
1213 |
Deadlock detected | esConcurrencyException |
1644 |
SIGNAL SQLSTATE '45000' raised by a generated procedure (stale version) |
esConcurrencyException |
try
{
category.Save();
}
catch (esConcurrencyException ex)
{
// Duplicate key, deadlock, or lock wait timeout
Console.WriteLine(ex.Message);
}
The 1644 entry only fires when the application uses the Stored Procedure save path (esSqlAccessType.StoredProcedure). Applications on the dynamic SQL path (DynamicSQL) rely on the row-count-zero detection that MySQL naturally raises for an UPDATE ... WHERE version = ? with no match.
Case Sensitivity
MySQL on Linux is case-sensitive for table and schema names (lower_case_table_names=0).
MySQL on Windows is case-insensitive. MariaDB is case-insensitive on all platforms.
EntitySpaces generates class metadata (meta.Source, meta.Destination) using the exact table names as they exist in the database at generation time. Always generate your EntitySpaces classes directly against the target server to guarantee case consistency.
| Platform | Behavior | Recommendation |
|---|---|---|
| MySQL on Linux | Case-sensitive | Generate classes against Linux MySQL |
| MySQL on Windows | Case-insensitive | No special action needed |
| MariaDB (all) | Case-insensitive | No special action needed |
β οΈ Known Limitations
IsComputed columns with a generic DEFAULT do not receive the value in-memory
The DynamicSQL path omits IsComputed columns from the INSERT (correct,
the DB DEFAULT should fill them), but it also skips the read-back for
those columns (the provider's IsComputed branch runs before the
HasDefault branch in BuildDynamicInsertCommand).
Concrete consequence: a column declared as
`createdat` DATETIME NULL DEFAULT CURRENT_TIMESTAMP
that is not one of the four special column names (DateAdded,
DateModified, AddedBy, ModifiedBy) behaves like this after
Save():
| Observation | Value |
|---|---|
| Row in the database | β Default applied correctly |
SELECT from any client |
β Returns the expected value |
entity.Createdat immediately after Save |
β Returns null |
entity.Createdat after LoadByPrimaryKey |
β Returns the expected value |
This is not a data-loss bug. The database is correct. Only the in-memory convenience (immediate availability of the server-generated value) is missing.
Workarounds
If the value must be available on the entity immediately after Save():
- Use a special column name. Columns named
DateAddedorDateModifiedare handled by a dedicated read-back branch and the value comes back immediately. - Set the value client-side before Save. If the timestamp has business meaning independent of insertion time, compute it in the application.
- Reload after Save.
entity.LoadByPrimaryKey(entity.Id)retrieves the correct value.
Tracked as future work
A provider-level fix would re-order the IsComputed and HasDefault
branches in BuildDynamicInsertCommand so that HasDefault columns
reach the Defaults bag even when IsComputed is also true. This is
deferred because DateAdded / DateModified would then receive two
read-backs (one from Defaults, one from the special-columns branch),
requiring a guard to avoid the duplicate.
The long-term fix belongs in the BO generator (Studio): stop classifying
plain DEFAULT columns as IsComputed when they are not one of the
four special columns. That change has broader implications for the
existing DateAdded / DateModified handling and is out of scope for
the current release.
Dependency Updates
MySqlConnector 2.6.2 β migrated from the legacy
MySql.Datadriver.MySqlConnectoris the actively maintained, .NET-8+-first ADO.NET provider for MySQL/MariaDB. Both drivers are wire-compatible, butMySqlConnectorhas:- First-class support for
System.Transactionswith explicit opt-in (previously automatic). - Consistent behavior across .NET Framework 4.8 and .NET 8β10.
- Faster, allocation-light parameter handling.
- First-class support for
System.Configuration.ConfigurationManager β updated from
10.0.13to10.0.14. Maintenance release. No API changes affecting EntitySpaces.
Quick Samples
Load a collection:
var customers = new CustomerCollection();
customers.LoadAll();
foreach (var customer in customers)
{
Console.WriteLine(customer.CompanyName);
}
Create, update, delete an entity:
var employee = new Employee();
employee.FirstName = "Joe";
employee.LastName = "Smith";
employee.Save(); // Create
employee.LastName = "Doe";
employee.Save(); // Update
employee.MarkAsDeleted();
employee.Save(); // Delete
MySQL connection string:
esProviderFactory.Factory = new EntitySpaces.Loader.esDataProviderFactory();
esConnectionElement conn = new esConnectionElement();
conn.Provider = "EntitySpaces.MySqlProvider";
conn.ConnectionString = "Server=myserver;Port=3306;Database=mydb;Uid=myuser;" +
"Pwd=mypassword;SslMode=Required;AllowPublicKeyRetrieval=True;";
esConfigSettings.ConnectionInfo.Connections.Add(conn);
SslMode note: MySQL 8.0 with
caching_sha2_password(default) requires eitherSslMode=RequiredorSslMode=Nonecombined withAllowPublicKeyRetrieval=True. UseSslMode=Requiredfor remote servers.
APPLY query (works identically on MySQL 8 and MariaDB):
var coll = new CustomerQuery("c", out var c)
.OuterApply<SalesorderQuery>(out var o, out var oCol, () =>
{
return (SalesorderQuery) new SalesorderQuery("o", out var subQuery)
.Select(subQuery.OrderId, subQuery.OrderDate)
.Top(2)
.Where(subQuery.CustId == c.CustId)
.OrderBy(subQuery.OrderDate.Descending);
})
.Select(c.CustId, c.CompanyName, oCol.OrderId)
.ToCollection<CustomerCollection>();
More usage examples (joins, paging, transactions, and the full Fluent SQL API): see the main EntitySpaces README.
Generating your entity classes
See Requires EntitySpaces Studio above.
If this provider saved you time, you can support its development via PayPal. Feedback is welcome through the 3βminute roadmap survey.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
| .NET Framework | net48 is compatible. net481 was computed. |
-
.NETFramework 4.8
- MySqlConnector (>= 2.6.2)
-
net10.0
- MySqlConnector (>= 2.6.2)
- System.Configuration.ConfigurationManager (>= 10.0.14)
-
net8.0
- MySqlConnector (>= 2.6.2)
- System.Configuration.ConfigurationManager (>= 10.0.14)
-
net9.0
- MySqlConnector (>= 2.6.2)
- System.Configuration.ConfigurationManager (>= 10.0.14)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Actively maintained fork of the EntitySpaces ORM, modernized for .NET Framework 4.8 through .NET 10 and aligned with EntitySpaces Studio 2026.11.
MySQL / MariaDB: LATERAL JOIN translation (native on MySQL 8.0.14+, ROW_NUMBER fallback on MariaDB), concurrency errors 1062, 1213 and 1205, MySqlConnector 2.6, MySQL 8.0.14+ and MariaDB 10.2+.
Full release notes: https://github.com/paulcordova/EntitySpaces/blob/master/CHANGELOG.md