diff --git a/api/src/Erp.Platform.Application/Note/NoteAppService.cs b/api/src/Erp.Platform.Application/Note/NoteAppService.cs index 2d515d17..cf254112 100644 --- a/api/src/Erp.Platform.Application/Note/NoteAppService.cs +++ b/api/src/Erp.Platform.Application/Note/NoteAppService.cs @@ -9,7 +9,6 @@ using Erp.Platform.BlobStoring; using Erp.Platform.Entities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Volo.Abp; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; @@ -57,8 +56,13 @@ public class NoteAppService : CrudAppService< if (stream == null) throw new UserFriendlyException("Dosya bulunamadı"); - var activities = await Repository.GetListAsync(); - var fileDto = activities + // Performans: TÜM notları çekmek yerine sadece bu dosyayı içereni bul + var queryable = await Repository.GetQueryableAsync(); + var notes = await AsyncExecuter.ToListAsync( + queryable.Where(a => a.FilesJson.Contains(savedFileName)) + ); + + var fileDto = notes .SelectMany(a => JsonSerializer.Deserialize>(a.FilesJson ?? "[]")) .FirstOrDefault(f => f.SavedFileName == savedFileName); @@ -86,35 +90,48 @@ public class NoteAppService : CrudAppService< if (!string.IsNullOrWhiteSpace(input.EntityId)) query = query.Where(a => a.EntityId == input.EntityId); - // 2️⃣ Sıralama (opsiyonel) + // 2️⃣ Sıralama (database'de) if (!string.IsNullOrWhiteSpace(input.Sorting)) query = query.OrderBy(input.Sorting); else query = query.OrderByDescending(a => a.CreationTime); - // 3️⃣ Paging + // 3️⃣ Toplam sayı (sayfalama öncesi) var totalCount = await AsyncExecuter.CountAsync(query); + + // 4️⃣ Paging var activities = await AsyncExecuter.ToListAsync( query.Skip(input.SkipCount).Take(input.MaxResultCount) ); - // 4️⃣ Kullanıcı bilgilerini al - var userIds = activities.Select(a => a.CreatorId).Distinct().ToList(); - var userQueryable = await _repositoryUser.GetQueryableAsync(); - var users = await userQueryable - .Where(u => userIds.Contains(u.Id)) - .Select(u => new { u.Id, u.UserName }) - .ToListAsync(); + // 5️⃣ Kullanıcı bilgilerini Dictionary ile al (N+1 önleme) + var userIds = activities.Where(a => a.CreatorId.HasValue) + .Select(a => a.CreatorId!.Value) + .Distinct() + .ToList(); + + var userDict = new Dictionary(); + if (userIds.Any()) + { + var userQueryable = await _repositoryUser.GetQueryableAsync(); + var users = await AsyncExecuter.ToListAsync( + userQueryable.Where(u => userIds.Contains(u.Id)) + .Select(u => new { u.Id, u.UserName }) + ); + userDict = users.ToDictionary(u => u.Id, u => u.UserName); + } - // 5️⃣ DTO map ve kullanıcı adı ekleme + // 6️⃣ DTO mapping - Dictionary lookup ile hızlı var noteDtos = activities.Select(a => { var dto = ObjectMapper.Map(a); - dto.CreateUserName = users.FirstOrDefault(u => u.Id == a.CreatorId)?.UserName ?? "Unknown"; + dto.CreateUserName = a.CreatorId.HasValue && userDict.TryGetValue(a.CreatorId.Value, out var userName) + ? userName + : "Unknown"; return dto; }).ToList(); - // 6️⃣ Sonuç dön + // 7️⃣ Sonuç dön return new PagedResultDto(totalCount, noteDtos); } diff --git a/api/src/Erp.Platform.Application/Public/PublicAppService.cs b/api/src/Erp.Platform.Application/Public/PublicAppService.cs index e9feeba0..6f8101ed 100644 --- a/api/src/Erp.Platform.Application/Public/PublicAppService.cs +++ b/api/src/Erp.Platform.Application/Public/PublicAppService.cs @@ -152,24 +152,28 @@ public class PublicAppService : PlatformAppService return dto; }).ToList(); - // ----------- KATEGORİLER (PostCount ile) ----------- - var allCategories = await _categoryRepository.GetListAsync(); - - var allPostQuery = await _postRepository.GetQueryableAsync(); - var counts = await AsyncExecuter.ToListAsync( - allPostQuery - .Where(p => p.IsPublished) - .GroupBy(p => p.CategoryId) - .Select(g => new { g.Key, Count = g.Count() }) + // ----------- KATEGORİLER (PostCount ile) - Optimize edildi ----------- + var categoryQueryable = await _categoryRepository.GetQueryableAsync(); + var postQueryableForCount = await _postRepository.GetQueryableAsync(); + + // Kategori listesi ve post sayıları tek sorguda + var categoriesWithCounts = await AsyncExecuter.ToListAsync( + from category in categoryQueryable + join post in postQueryableForCount.Where(p => p.IsPublished) + on category.Id equals post.CategoryId into postGroup + select new + { + Category = category, + PostCount = postGroup.Count() + } ); - var countDict = counts.ToDictionary(x => x.Key, x => x.Count); - - var categoryDtos = ObjectMapper.Map, List>(allCategories); - foreach (var dto in categoryDtos) + var categoryDtos = categoriesWithCounts.Select(x => { - dto.PostCount = countDict.GetOrDefault(dto.Id); - } + var dto = ObjectMapper.Map(x.Category); + dto.PostCount = x.PostCount; + return dto; + }).ToList(); return new BlogPostAndCategoriesDto { @@ -180,13 +184,21 @@ public class PublicAppService : PlatformAppService private async Task GetPostAsync(Guid id) { - var post = await _postRepository.GetAsync(id); - var dto = ObjectMapper.Map(post); - - // Get category - dto.Category = ObjectMapper.Map( - await _categoryRepository.GetAsync(post.CategoryId) + // Tek sorguda post ve category'yi çek (N+1 önleme) + var queryable = await _postRepository.GetQueryableAsync(); + var categoryQueryable = await _categoryRepository.GetQueryableAsync(); + + var result = await AsyncExecuter.FirstOrDefaultAsync( + from post in queryable.Where(p => p.Id == id) + join category in categoryQueryable on post.CategoryId equals category.Id + select new { Post = post, Category = category } ); + + if (result == null) + throw new EntityNotFoundException(typeof(BlogPost)); + + var dto = ObjectMapper.Map(result.Post); + dto.Category = ObjectMapper.Map(result.Category); return dto; } @@ -204,9 +216,13 @@ public class PublicAppService : PlatformAppService public async Task> GetProductListAsync() { - var products = await _productRepository.GetListAsync(); + // Performans: Sıralamayı database'de yap + var queryable = await _productRepository.GetQueryableAsync(); + var products = await AsyncExecuter.ToListAsync( + queryable.OrderBy(p => p.Order) + ); - return ObjectMapper.Map, List>(products.OrderBy(p => p.Order).ToList()); + return ObjectMapper.Map, List>(products); } public async Task> GetPaymentMethodListAsync() diff --git a/api/src/Erp.Platform.Application/Question/QuestionAppService.cs b/api/src/Erp.Platform.Application/Question/QuestionAppService.cs index d49d3bdb..3aa82390 100644 --- a/api/src/Erp.Platform.Application/Question/QuestionAppService.cs +++ b/api/src/Erp.Platform.Application/Question/QuestionAppService.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Erp.Platform.Entities; using Erp.Platform.Questions; -using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services;