From 69e23d9d2a9cbb3cb33797d63881cfcbea526e59 Mon Sep 17 00:00:00 2001 From: Yaojia Wang Date: Mon, 3 Nov 2025 16:34:55 +0100 Subject: [PATCH] fix(backend): Fix LINQ translation issue in UserTenantRoleRepository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed EF Core LINQ query translation error that caused 500 errors in Login and Refresh Token endpoints. Problem: - UserTenantRoleRepository was using `.Value` property accessor on value objects (UserId, TenantId) in LINQ queries - EF Core could not translate expressions like `utr.UserId.Value == userId` to SQL - This caused System.InvalidOperationException with message "The LINQ expression could not be translated" - Resulted in 500 Internal Server Error for Login and Refresh Token endpoints Solution: - Create value object instances (UserId.Create(), TenantId.Create()) before query - Compare value objects directly instead of accessing .Value property - EF Core can translate value object comparison due to HasConversion configuration - Removed .Include(utr => utr.User) since User navigation is ignored in EF config Impact: - Login endpoint now works correctly (200 OK) - Refresh Token endpoint now works correctly (200 OK) - RBAC role assignment and retrieval working properly - Resolves BUG-003 and BUG-004 from QA test report Test Results: - Before fix: 57% pass rate (8/14 tests) - After fix: ~79% pass rate (11/14 tests) - core functionality restored - Diagnostic test: All critical endpoints (Register, Login, Refresh) passing Files Changed: - UserTenantRoleRepository.cs: Fixed all three query methods (GetByUserAndTenantAsync, GetByUserAsync, GetByTenantAsync) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Repositories/UserTenantRoleRepository.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/colaflow-api/src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/Persistence/Repositories/UserTenantRoleRepository.cs b/colaflow-api/src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/Persistence/Repositories/UserTenantRoleRepository.cs index f90cd09..dcbc04a 100644 --- a/colaflow-api/src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/Persistence/Repositories/UserTenantRoleRepository.cs +++ b/colaflow-api/src/Modules/Identity/ColaFlow.Modules.Identity.Infrastructure/Persistence/Repositories/UserTenantRoleRepository.cs @@ -1,4 +1,5 @@ using ColaFlow.Modules.Identity.Domain.Aggregates.Users; +using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants; using ColaFlow.Modules.Identity.Domain.Repositories; using Microsoft.EntityFrameworkCore; @@ -18,9 +19,13 @@ public class UserTenantRoleRepository : IUserTenantRoleRepository Guid tenantId, CancellationToken cancellationToken = default) { + // Create value objects to avoid LINQ translation issues with .Value property + var userIdVO = UserId.Create(userId); + var tenantIdVO = TenantId.Create(tenantId); + return await _context.UserTenantRoles .FirstOrDefaultAsync( - utr => utr.UserId.Value == userId && utr.TenantId.Value == tenantId, + utr => utr.UserId == userIdVO && utr.TenantId == tenantIdVO, cancellationToken); } @@ -28,8 +33,11 @@ public class UserTenantRoleRepository : IUserTenantRoleRepository Guid userId, CancellationToken cancellationToken = default) { + // Create value object to avoid LINQ translation issues with .Value property + var userIdVO = UserId.Create(userId); + return await _context.UserTenantRoles - .Where(utr => utr.UserId.Value == userId) + .Where(utr => utr.UserId == userIdVO) .ToListAsync(cancellationToken); } @@ -37,9 +45,12 @@ public class UserTenantRoleRepository : IUserTenantRoleRepository Guid tenantId, CancellationToken cancellationToken = default) { + // Create value object to avoid LINQ translation issues with .Value property + var tenantIdVO = TenantId.Create(tenantId); + return await _context.UserTenantRoles - .Where(utr => utr.TenantId.Value == tenantId) - .Include(utr => utr.User) // Include user details for tenant management + .Where(utr => utr.TenantId == tenantIdVO) + // Note: User navigation is ignored in EF config, so Include is skipped .ToListAsync(cancellationToken); }