fix(backend+tests): reactivate endpoint 500 + test schema mismatches (PRC-001)
Three bugs surfaced while user smoke-testing Reactivate: 1. ReactivateAsync opened a SECOND connection for GetByIdAsync after the SP call, inside the ambient TransactionScope. This promoted the tx to DTC (distributed) which requires MSDTC — typically not enabled on dev/prod servers. The API returned an opaque 500. Fix: run the post-SP SELECT on the SAME connection (local tx stays lightweight / LTM). 2. Agent 1's V023 test refactor wrote 'INSERT INTO dbo.ProductType (Nombre, Codigo, Activo)' in 2 test files — but dbo.ProductType has no 'Codigo' or 'Activo' columns (schema is Nombre + IsActive + flags + multimedia limits). Fix: use '(Nombre, HasDuration, RequiresText, RequiresCategory, IsBundle, AllowImages)' matching the other test files (ProductQueryRepositoryTests, ProductRepositoryTests, ProductPriceRepositoryIntegrationTests). 3. SqlTestFixture.EnsureV021SchemaAsync unconditionally ALTERed the V021-era SPs with '@MedioId' body. On second fixture run after V023 had already refactored the table, ALTER PROCEDURE body referenced a MedioId column that no longer existed — 'Invalid column name MedioId'. Fix: guard the V021 SP ALTERs + seedV022 behind 'MedioId column exists' check. If V023 already dropped MedioId, skip V021 re-install; EnsureV023SchemaAsync still recreates SPs with @ProductTypeId. 4. PricingExceptionTests still used 'medioId:' named-arg + '.MedioId' — Agent 2 renamed the exception property but not these 6 test references. Tests: 1297/1297 Application.Tests green.
This commit is contained in:
@@ -237,6 +237,11 @@ public sealed class ChargeableCharConfigRepository : IChargeableCharConfigReposi
|
||||
long id,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
// IMPORTANT: the SP invocation and the subsequent SELECT MUST run on the SAME connection.
|
||||
// Opening a second connection within the ambient TransactionScope would promote the
|
||||
// transaction to DTC (distributed) — and MSDTC is typically not enabled on dev/prod
|
||||
// servers. That promotion surfaces as an opaque 500 at the API boundary. Keeping both
|
||||
// commands on a single SqlConnection keeps the tx as a local LTM (lightweight transaction).
|
||||
var p = new DynamicParameters();
|
||||
p.Add("@Id", id, DbType.Int64);
|
||||
|
||||
@@ -270,11 +275,20 @@ public sealed class ChargeableCharConfigRepository : IChargeableCharConfigReposi
|
||||
throw new ChargeableCharConfigReactivationNotAllowedException(id, "POSTERIOR_ROWS_EXIST");
|
||||
}
|
||||
|
||||
// Fetch the reactivated row to return its current state.
|
||||
var reactivated = await GetByIdAsync(id, ct);
|
||||
return reactivated
|
||||
?? throw new ChargeableCharConfigInvalidException(
|
||||
nameof(id), $"ChargeableCharConfig with Id={id} not found after reactivation (unexpected).");
|
||||
// Fetch the reactivated row on the SAME connection (avoids DTC promotion).
|
||||
const string selectSql = """
|
||||
SELECT Id, ProductTypeId, Symbol, Category, PricePerUnit, ValidFrom, ValidTo, IsActive
|
||||
FROM dbo.ChargeableCharConfig
|
||||
WHERE Id = @Id
|
||||
""";
|
||||
|
||||
var row = await connection.QuerySingleOrDefaultAsync<ChargeableCharConfigRow>(
|
||||
new CommandDefinition(selectSql, new { Id = id }, cancellationToken: ct));
|
||||
|
||||
return row is null
|
||||
? throw new ChargeableCharConfigInvalidException(
|
||||
nameof(id), $"ChargeableCharConfig with Id={id} not found after reactivation (unexpected).")
|
||||
: MapRow(row);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
Reference in New Issue
Block a user