Fix: Load navigation properties before projection to ensure variants are included

**Problem**: EF Core was not materializing Variants navigation property when using
.Select() projection directly in the query. The .Include() was being ignored.

**Solution**: Changed approach to:
1. Load entities with .Include() + .ToListAsync() first
2. Then project to DTO with in-memory .Select()

This ensures navigation properties are fully loaded before mapping to DTOs.

**Impact**: Variants will now properly appear in all product API responses.

🤖 Generated with Claude Code
https://claude.com/claude-code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
SysAdmin 2025-10-04 17:48:30 +01:00
parent 22e910862a
commit b05645d526

View File

@ -18,13 +18,16 @@ public class ProductService : IProductService
public async Task<IEnumerable<ProductDto>> GetAllProductsAsync() public async Task<IEnumerable<ProductDto>> GetAllProductsAsync()
{ {
return await _context.Products var products = await _context.Products
.Include(p => p.Category) .Include(p => p.Category)
.Include(p => p.Photos) .Include(p => p.Photos)
.Include(p => p.MultiBuys) .Include(p => p.MultiBuys)
.Include(p => p.Variants) .Include(p => p.Variants)
.Where(p => p.IsActive) .Where(p => p.IsActive)
.Select(p => new ProductDto .AsNoTracking()
.ToListAsync();
return products.Select(p => new ProductDto
{ {
Id = p.Id, Id = p.Id,
Name = p.Name, Name = p.Name,
@ -73,19 +76,21 @@ public class ProductService : IProductService
CreatedAt = v.CreatedAt, CreatedAt = v.CreatedAt,
UpdatedAt = v.UpdatedAt UpdatedAt = v.UpdatedAt
}).ToList() }).ToList()
}) }).ToList();
.ToListAsync();
} }
public async Task<IEnumerable<ProductDto>> GetProductsByCategoryAsync(Guid categoryId) public async Task<IEnumerable<ProductDto>> GetProductsByCategoryAsync(Guid categoryId)
{ {
return await _context.Products var products = await _context.Products
.Include(p => p.Category) .Include(p => p.Category)
.Include(p => p.Photos) .Include(p => p.Photos)
.Include(p => p.MultiBuys) .Include(p => p.MultiBuys)
.Include(p => p.Variants) .Include(p => p.Variants)
.Where(p => p.IsActive && p.CategoryId == categoryId) .Where(p => p.IsActive && p.CategoryId == categoryId)
.Select(p => new ProductDto .AsNoTracking()
.ToListAsync();
return products.Select(p => new ProductDto
{ {
Id = p.Id, Id = p.Id,
Name = p.Name, Name = p.Name,
@ -134,8 +139,7 @@ public class ProductService : IProductService
CreatedAt = v.CreatedAt, CreatedAt = v.CreatedAt,
UpdatedAt = v.UpdatedAt UpdatedAt = v.UpdatedAt
}).ToList() }).ToList()
}) }).ToList();
.ToListAsync();
} }
public async Task<ProductDto?> GetProductByIdAsync(Guid id) public async Task<ProductDto?> GetProductByIdAsync(Guid id)