Note, Public ve Question AppService

This commit is contained in:
Sedat Öztürk 2026-02-04 21:51:18 +03:00
parent 1f97581874
commit 2aa5e99da2
3 changed files with 71 additions and 40 deletions

View file

@ -9,7 +9,6 @@ using Erp.Platform.BlobStoring;
using Erp.Platform.Entities; using Erp.Platform.Entities;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
@ -57,8 +56,13 @@ public class NoteAppService : CrudAppService<
if (stream == null) if (stream == null)
throw new UserFriendlyException("Dosya bulunamadı"); throw new UserFriendlyException("Dosya bulunamadı");
var activities = await Repository.GetListAsync(); // Performans: TÜM notları çekmek yerine sadece bu dosyayı içereni bul
var fileDto = activities var queryable = await Repository.GetQueryableAsync();
var notes = await AsyncExecuter.ToListAsync(
queryable.Where(a => a.FilesJson.Contains(savedFileName))
);
var fileDto = notes
.SelectMany(a => JsonSerializer.Deserialize<List<NoteFileDto>>(a.FilesJson ?? "[]")) .SelectMany(a => JsonSerializer.Deserialize<List<NoteFileDto>>(a.FilesJson ?? "[]"))
.FirstOrDefault(f => f.SavedFileName == savedFileName); .FirstOrDefault(f => f.SavedFileName == savedFileName);
@ -86,35 +90,48 @@ public class NoteAppService : CrudAppService<
if (!string.IsNullOrWhiteSpace(input.EntityId)) if (!string.IsNullOrWhiteSpace(input.EntityId))
query = query.Where(a => a.EntityId == input.EntityId); query = query.Where(a => a.EntityId == input.EntityId);
// 2⃣ Sıralama (opsiyonel) // 2⃣ Sıralama (database'de)
if (!string.IsNullOrWhiteSpace(input.Sorting)) if (!string.IsNullOrWhiteSpace(input.Sorting))
query = query.OrderBy(input.Sorting); query = query.OrderBy(input.Sorting);
else else
query = query.OrderByDescending(a => a.CreationTime); query = query.OrderByDescending(a => a.CreationTime);
// 3Paging // 3Toplam sayı (sayfalama öncesi)
var totalCount = await AsyncExecuter.CountAsync(query); var totalCount = await AsyncExecuter.CountAsync(query);
// 4⃣ Paging
var activities = await AsyncExecuter.ToListAsync( var activities = await AsyncExecuter.ToListAsync(
query.Skip(input.SkipCount).Take(input.MaxResultCount) query.Skip(input.SkipCount).Take(input.MaxResultCount)
); );
// 4⃣ Kullanıcı bilgilerini al // 5⃣ Kullanıcı bilgilerini Dictionary ile al (N+1 önleme)
var userIds = activities.Select(a => a.CreatorId).Distinct().ToList(); var userIds = activities.Where(a => a.CreatorId.HasValue)
var userQueryable = await _repositoryUser.GetQueryableAsync(); .Select(a => a.CreatorId!.Value)
var users = await userQueryable .Distinct()
.Where(u => userIds.Contains(u.Id)) .ToList();
.Select(u => new { u.Id, u.UserName })
.ToListAsync();
// 5⃣ DTO map ve kullanıcı adı ekleme var userDict = new Dictionary<Guid, string>();
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);
}
// 6⃣ DTO mapping - Dictionary lookup ile hızlı
var noteDtos = activities.Select(a => var noteDtos = activities.Select(a =>
{ {
var dto = ObjectMapper.Map<Note, NoteDto>(a); var dto = ObjectMapper.Map<Note, NoteDto>(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; return dto;
}).ToList(); }).ToList();
// 6⃣ Sonuç dön // 7️⃣ Sonuç dön
return new PagedResultDto<NoteDto>(totalCount, noteDtos); return new PagedResultDto<NoteDto>(totalCount, noteDtos);
} }

View file

@ -152,24 +152,28 @@ public class PublicAppService : PlatformAppService
return dto; return dto;
}).ToList(); }).ToList();
// ----------- KATEGORİLER (PostCount ile) ----------- // ----------- KATEGORİLER (PostCount ile) - Optimize edildi -----------
var allCategories = await _categoryRepository.GetListAsync(); var categoryQueryable = await _categoryRepository.GetQueryableAsync();
var postQueryableForCount = await _postRepository.GetQueryableAsync();
var allPostQuery = await _postRepository.GetQueryableAsync(); // Kategori listesi ve post sayıları tek sorguda
var counts = await AsyncExecuter.ToListAsync( var categoriesWithCounts = await AsyncExecuter.ToListAsync(
allPostQuery from category in categoryQueryable
.Where(p => p.IsPublished) join post in postQueryableForCount.Where(p => p.IsPublished)
.GroupBy(p => p.CategoryId) on category.Id equals post.CategoryId into postGroup
.Select(g => new { g.Key, Count = g.Count() }) select new
{
Category = category,
PostCount = postGroup.Count()
}
); );
var countDict = counts.ToDictionary(x => x.Key, x => x.Count); var categoryDtos = categoriesWithCounts.Select(x =>
var categoryDtos = ObjectMapper.Map<List<BlogCategory>, List<BlogCategoryDto>>(allCategories);
foreach (var dto in categoryDtos)
{ {
dto.PostCount = countDict.GetOrDefault(dto.Id); var dto = ObjectMapper.Map<BlogCategory, BlogCategoryDto>(x.Category);
} dto.PostCount = x.PostCount;
return dto;
}).ToList();
return new BlogPostAndCategoriesDto return new BlogPostAndCategoriesDto
{ {
@ -180,14 +184,22 @@ public class PublicAppService : PlatformAppService
private async Task<BlogPostDto> GetPostAsync(Guid id) private async Task<BlogPostDto> GetPostAsync(Guid id)
{ {
var post = await _postRepository.GetAsync(id); // Tek sorguda post ve category'yi çek (N+1 önleme)
var dto = ObjectMapper.Map<BlogPost, BlogPostDto>(post); var queryable = await _postRepository.GetQueryableAsync();
var categoryQueryable = await _categoryRepository.GetQueryableAsync();
// Get category var result = await AsyncExecuter.FirstOrDefaultAsync(
dto.Category = ObjectMapper.Map<BlogCategory, BlogCategoryDto>( from post in queryable.Where(p => p.Id == id)
await _categoryRepository.GetAsync(post.CategoryId) 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<BlogPost, BlogPostDto>(result.Post);
dto.Category = ObjectMapper.Map<BlogCategory, BlogCategoryDto>(result.Category);
return dto; return dto;
} }
@ -204,9 +216,13 @@ public class PublicAppService : PlatformAppService
public async Task<List<ProductDto>> GetProductListAsync() public async Task<List<ProductDto>> 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<Product>, List<ProductDto>>(products.OrderBy(p => p.Order).ToList()); return ObjectMapper.Map<List<Product>, List<ProductDto>>(products);
} }
public async Task<List<PaymentMethodDto>> GetPaymentMethodListAsync() public async Task<List<PaymentMethodDto>> GetPaymentMethodListAsync()

View file

@ -1,10 +1,8 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Erp.Platform.Entities; using Erp.Platform.Entities;
using Erp.Platform.Questions; using Erp.Platform.Questions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;