Files
KArtSell.Aegis/src/KArtSell.Modules.SignalEngine/DapperMappingBootstrap.cs
T
kjh2064 8ed2bcf56f fix: Dapper underscore-mapping race condition affects AuditSql too, not just TradeSql
The static-ctor guard added to TradeSql in the previous commit was a
symptom fix. Confirmed the same bug independently affects AuditSql:
running the Compliance test filter in isolation (no other class that
happens to touch a BuildingBlocks type first) reproduced the identical
failure mode - every snake_case column (event_type, purge_status, ...)
silently mapped to null.

Root cause: KArtSell.BuildingBlocks.Data.DapperBootstrap's
[ModuleInitializer] only runs once that assembly is actually loaded,
and a `using` directive for a BuildingBlocks namespace does not force
that load - only an executed reference to one of its types does. Any
Sql class that never actually touches a BuildingBlocks type at runtime
is exposed, and this is a property of *when* a given test/request
happens to run relative to everything else in the process, not of any
one class.

Replaced the ad-hoc TradeSql static ctor with one [ModuleInitializer]
per module assembly (KArtSell.Modules.ModelOperations,
KArtSell.Modules.SignalEngine). Every Sql/reader class lives inside its
own module's assembly, so a module initializer there is guaranteed to
run before any of them are used, independent of BuildingBlocks or
load order. Verified both KArtSell.Integration.Tests.Compliance and
.TradeExecution now pass 100% run in full isolation, not just as part
of the full suite.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-07 23:36:08 +09:00

22 lines
821 B
C#

using System.Runtime.CompilerServices;
namespace KArtSell.Modules.SignalEngine;
/// <summary>
/// See KArtSell.Modules.ModelOperations.DapperMappingBootstrap for the full rationale: Dapper's
/// snake_case-to-PascalCase column mapping is a process-wide static flag set via
/// KArtSell.BuildingBlocks.Data.DapperBootstrap's [ModuleInitializer], which only fires once
/// that assembly is loaded. This mirrors it locally so every Sql/reader class defined in this
/// assembly is guaranteed the mapping is on before its first query, regardless of load order.
/// </summary>
internal static class DapperMappingBootstrap
{
#pragma warning disable CA2255
[ModuleInitializer]
#pragma warning restore CA2255
public static void Initialize()
{
Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
}
}