Switches the database from SQL Server to MariaDB

The target Pi only has MariaDB, and SQL Server has no ARM64 build at
all - not a config problem, a real gap discovered during deployment
setup. Swapped the EF Core provider, regenerated every migration,
updated connection strings and the backup script everywhere they
appear.

Took two tries to land on a provider that actually works: Pomelo
builds fine against this project's EF Core 10 packages but fails at
runtime (it's compiled against 9's internal API surface, which moved
in 10 wherever Identity/DataProtection force the newer packages).
Oracle's official provider builds and migrates fine but has a real
MariaDB bug in its own migration-lock code, reproduced against a live
database. Kept Oracle's provider and worked around just that one
broken method - everything else it does is correct - rather than
give up more of the stack to chase a workaround.

Verified against a real local MariaDB end to end: all three
migrations applied, both hosts start clean, full suite still green.
This commit is contained in:
2026-07-29 11:59:09 +02:00
parent 579e0ceaac
commit 33d18ebbf8
33 changed files with 575 additions and 1367 deletions
@@ -1,5 +1,5 @@
using FluentAssertions;
using Microsoft.Data.SqlClient;
using MySql.Data.MySqlClient;
using SlpModularCms.Core.Hosting;
using Xunit;
@@ -47,9 +47,9 @@ public class DatabaseMigrationExtensionsTests
public static TheoryData<Exception> TransientFailures() =>
[
MakeSqlException(),
MakeMySqlException(),
new TimeoutException("Connect Timeout expired."),
new InvalidOperationException("wrapper", MakeSqlException()),
new InvalidOperationException("wrapper", MakeMySqlException()),
];
public static TheoryData<Exception> NonTransientFailures() =>
@@ -71,18 +71,18 @@ public class DatabaseMigrationExtensionsTests
}
/// <summary>
/// <see cref="SqlException"/> has no public constructor, so one is produced through the
/// <see cref="MySqlException"/> has no public constructor, so one is produced through the
/// framework's own factory path via reflection.
/// </summary>
private static Exception MakeSqlException()
private static Exception MakeMySqlException()
{
try
{
// Deliberately unreachable host and a very short timeout: this genuinely produces a
// SqlException rather than a hand-built stand-in, so the classifier is tested against
// MySqlException rather than a hand-built stand-in, so the classifier is tested against
// the real type it will encounter in production.
using var connection = new SqlConnection(
"Server=localhost,9;Database=none;User Id=sa;Password=none;Connect Timeout=1;TrustServerCertificate=True");
using var connection = new MySqlConnection(
"Server=localhost;Port=9;Database=none;Uid=none;Pwd=none;Connection Timeout=1");
connection.Open();
}
catch (Exception ex)