diff --git a/backend/WorkClub.Infrastructure/Data/Interceptors/TenantDbConnectionInterceptor.cs b/backend/WorkClub.Infrastructure/Data/Interceptors/TenantDbConnectionInterceptor.cs index f4a5894..b7e8623 100644 --- a/backend/WorkClub.Infrastructure/Data/Interceptors/TenantDbConnectionInterceptor.cs +++ b/backend/WorkClub.Infrastructure/Data/Interceptors/TenantDbConnectionInterceptor.cs @@ -1,88 +1,76 @@ using System.Data.Common; -using Finbuckle.MultiTenant; -using Finbuckle.MultiTenant.Abstractions; +using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.Extensions.Logging; using Npgsql; namespace WorkClub.Infrastructure.Data.Interceptors; -public class TenantDbConnectionInterceptor : DbConnectionInterceptor +public class TenantDbConnectionInterceptor : DbCommandInterceptor { - private readonly IMultiTenantContextAccessor _tenantAccessor; + private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger _logger; public TenantDbConnectionInterceptor( - IMultiTenantContextAccessor tenantAccessor, + IHttpContextAccessor httpContextAccessor, ILogger logger) { - _tenantAccessor = tenantAccessor; + _httpContextAccessor = httpContextAccessor; _logger = logger; } - public override async ValueTask ConnectionOpeningAsync( - DbConnection connection, - ConnectionEventData eventData, - InterceptionResult result, + public override ValueTask> ReaderExecutingAsync( + DbCommand command, + CommandEventData eventData, + InterceptionResult result, CancellationToken cancellationToken = default) { - await base.ConnectionOpeningAsync(connection, eventData, result, cancellationToken); - - var tenantId = _tenantAccessor.MultiTenantContext?.TenantInfo?.Identifier; - - if (string.IsNullOrWhiteSpace(tenantId)) - { - _logger.LogWarning("No tenant context available for database connection"); - return result; - } - - if (connection is NpgsqlConnection npgsqlConnection) - { - await using var command = npgsqlConnection.CreateCommand(); - command.CommandText = $"SET LOCAL app.current_tenant_id = '{tenantId}'"; - - try - { - await command.ExecuteNonQueryAsync(cancellationToken); - _logger.LogDebug("Set tenant context for database connection: {TenantId}", tenantId); - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to set tenant context for connection"); - throw; - } - } - - return result; + SetTenantContext(command); + return base.ReaderExecutingAsync(command, eventData, result, cancellationToken); } - public override void ConnectionOpened(DbConnection connection, ConnectionEndEventData eventData) + public override InterceptionResult ReaderExecuting( + DbCommand command, + CommandEventData eventData, + InterceptionResult result) { - base.ConnectionOpened(connection, eventData); + SetTenantContext(command); + return base.ReaderExecuting(command, eventData, result); + } - var tenantId = _tenantAccessor.MultiTenantContext?.TenantInfo?.Identifier; + public override ValueTask> NonQueryExecutingAsync( + DbCommand command, + CommandEventData eventData, + InterceptionResult result, + CancellationToken cancellationToken = default) + { + SetTenantContext(command); + return base.NonQueryExecutingAsync(command, eventData, result, cancellationToken); + } - if (string.IsNullOrWhiteSpace(tenantId)) + public override InterceptionResult NonQueryExecuting( + DbCommand command, + CommandEventData eventData, + InterceptionResult result) + { + SetTenantContext(command); + return base.NonQueryExecuting(command, eventData, result); + } + + private void SetTenantContext(DbCommand command) + { + var tenantId = _httpContextAccessor.HttpContext?.Items["TenantId"] as string; + + if (!string.IsNullOrWhiteSpace(tenantId) && command.Connection is NpgsqlConnection conn) { - _logger.LogWarning("No tenant context available for database connection"); - return; + // Prepend SET LOCAL to set tenant context + // Note: EF Core creates implicit transactions for queries, so SET LOCAL will work + command.CommandText = $"SET LOCAL app.current_tenant_id = '{tenantId}'; " + command.CommandText; + _logger.LogInformation("SetTenantContext: Prepended SET LOCAL for tenant {TenantId}", tenantId); } - - if (connection is NpgsqlConnection npgsqlConnection) + else { - using var command = npgsqlConnection.CreateCommand(); - command.CommandText = $"SET LOCAL app.current_tenant_id = '{tenantId}'"; - - try - { - command.ExecuteNonQuery(); - _logger.LogDebug("Set tenant context for database connection: {TenantId}", tenantId); - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to set tenant context for connection"); - throw; - } + _logger.LogWarning("ReaderExecuting: No tenant context available (tenantId={TenantId})", tenantId ?? "null"); } } }