fix(backend): Fix LINQ translation issue in UserTenantRoleRepository

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 <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2025-11-03 16:34:55 +01:00
parent 738d32428a
commit 69e23d9d2a

View File

@@ -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);
}