Dla takich modeli:
public class ProductModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public decimal? Discount { get; set; }
public int ReviewCount { get; set; }
public int RateCount { get; set; }
public decimal AverageRate { get; set; }
public int? UserRate { get; set; }
public IList<ReviewModel> Reviews { get; set; }
public IList<PhotoModel> Photos { get; set; }
}
public class ReviewModel
{
public int Id { get; set; }
public string CustomerId { get; set; }
public string CustomerFirstName { get; set; }
public int Stars { get; set; }
public string Content { get; set; }
public int ApprovementCount { get; set; }
public bool WasApprovedByUser { get; set; }
}
public class PhotoModel
{
public int Id { get; set; }
public string Description { get; set; }
public bool IsMain { get; set; }
}
przy takiej konfiguracji
string currentCustomerId = null;
CreateMap<Product, ProductModel>()
.ForMember(dest => dest.ReviewCount, opt => opt.MapFrom(src => src.Reviews.Count()))
.ForMember(dest => dest.UserRate, opt => opt.MapFrom(src => src.Rates.Where(r => r.CustomerId == currentCustomerId).Select(r => r.Stars).FirstOrDefault()));
CreateMap<ProductPhoto, PhotoModel>();
CreateMap<Review, ReviewModel>()
.ForMember(dest => dest.ApprovementCount, opt => opt.MapFrom(src => src.Approvements.Count()))
.ForMember(dest => dest.WasApprovedByUser, opt => opt.MapFrom(src => src.Approvements.Any(a => a.CustomerId == currentCustomerId)));
przy użyciu ProjectTo
EF Core generuje taki SQL:
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (22ms) [Parameters=[@__request_ProductId_1='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [dtoProduct].[AverageRate], [dtoProduct].[Description], [dtoProduct].[Discount], [dtoProduct].[Id], [dtoProduct].[Name], [dtoProduct].[Price], [dtoProduct].[RateCount], (
SELECT COUNT(*)
FROM [Reviews] AS [r]
WHERE [dtoProduct].[Id] = [r].[ProductId]
) AS [ReviewCount], COALESCE((
SELECT TOP(1) [r0].[Stars]
FROM [Rates] AS [r0]
WHERE [r0].[CustomerId] IS NULL AND ([dtoProduct].[Id] = [r0].[ProductId])
), 0) AS [UserRate]
FROM [Products] AS [dtoProduct]
WHERE [dtoProduct].[Id] = @__request_ProductId_1
ORDER BY [dtoProduct].[Id]
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (3ms) [Parameters=[@__request_ProductId_1='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SELECT [t].[Id], [dtoProduct.Photos].[Description], [dtoProduct.Photos].[Id] AS [Id0], [dtoProduct.Photos].[IsMain], [dtoProduct.Photos].[ProductId]
FROM [ProductPhotos] AS [dtoProduct.Photos]
INNER JOIN (
SELECT TOP(1) [dtoProduct0].[Id]
FROM [Products] AS [dtoProduct0]
WHERE [dtoProduct0].[Id] = @__request_ProductId_1
ORDER BY [dtoProduct0].[Id]
) AS [t] ON [dtoProduct.Photos].[ProductId] = [t].[Id]
ORDER BY [t].[Id]
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (6ms) [Parameters=[@__request_ProductId_1='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SELECT [t0].[Id], (
SELECT COUNT(*)
FROM [ReviewApprovements] AS [r1]
WHERE [dtoProduct.Reviews].[Id] = [r1].[ReviewId]
) AS [ApprovementCount], [dtoProduct.Reviews].[Content], [dtoReview.Customer].[FirstName] AS [CustomerFirstName], [dtoProduct.Reviews].[CustomerId], [dtoProduct.Reviews].[Id] AS [Id0], [dtoProduct.Reviews].[Stars], (
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM [ReviewApprovements] AS [a]
WHERE [a].[CustomerId] IS NULL AND ([dtoProduct.Reviews].[Id] = [a].[ReviewId]))
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END
) AS [WasApprovedByUser], [dtoProduct.Reviews].[ProductId]
FROM [Reviews] AS [dtoProduct.Reviews]
LEFT JOIN [Customers] AS [dtoReview.Customer] ON [dtoProduct.Reviews].[CustomerId] = [dtoReview.Customer].[Id]
INNER JOIN (
SELECT TOP(1) [dtoProduct1].[Id]
FROM [Products] AS [dtoProduct1]
WHERE [dtoProduct1].[Id] = @__request_ProductId_1
ORDER BY [dtoProduct1].[Id]
) AS [t0] ON [dtoProduct.Reviews].[ProductId] = [t0].[Id]
ORDER BY [t0].[Id]
Skoro i tak EF Core wysyła kilka zapytań, to chyba temat można zamknąć.