Add migration to rename index and create stored procedure for user weekly balances
Build and Deploy to Kubernetes / build-and-deploy (push) Successful in 9m55s

- Added migration to rename index from IX_NetworkWeeklyBalances_PackageId to IX_NetworkWeeklyBalance_PackageId in the NetworkWeeklyBalances table.
- Created stored procedure sp_GetUserWeeklyBalances to retrieve weekly balances with pagination and various filters.
This commit is contained in:
masoodafar-web
2026-05-04 00:36:31 +03:30
parent c5dd1a2ef5
commit e4279f3d05
7 changed files with 5334 additions and 62 deletions
@@ -15,75 +15,49 @@ public class GetUserWeeklyBalancesQueryHandler : IRequestHandler<GetUserWeeklyBa
public async Task<GetUserWeeklyBalancesResponseDto> Handle(GetUserWeeklyBalancesQuery request, CancellationToken cancellationToken)
{
var query = _context.NetworkWeeklyBalances
.Include(x => x.WeekDefinition)
.Include(x => x.User)
.Include(x => x.Package)
.AsNoTracking()
.AsQueryable();
var pageSize = request.PaginationState?.PageSize > 0 ? request.PaginationState.PageSize : PaginationDefaults.PageSize;
var pageNumber = request.PaginationState?.PageNumber > 0 ? request.PaginationState.PageNumber : PaginationDefaults.PageNumber;
// UserId > 0 → filter by that user
// UserId == 0 or null → show ALL users (admin mode)
// Customer endpoints resolve UserId from JWT before calling this handler
long? userId = request.UserId;
// تشخیص جهت مرتب‌سازی از SortBy (پیش‌فرض: نزولی)
var sortBy = request.SortBy ?? "-WeekDefinitionId";
int sortDescending = sortBy.StartsWith("-") ? 1 : 0;
if (userId.HasValue && userId.Value > 0)
{
query = query.Where(x => x.UserId == userId.Value);
}
long? userId = request.UserId.HasValue && request.UserId.Value > 0 ? request.UserId : null;
long? weekDefinitionId = request.WeekDefinitionId.HasValue ? request.WeekDefinitionId : null;
long? packageId = request.PackageId.HasValue && request.PackageId.Value > 0 ? request.PackageId : null;
int onlyActive = request.OnlyActive.HasValue && request.OnlyActive.Value ? 1 : 0;
// فیلتر بر اساس WeekDefinitionId (روش ترجیحی)
if (request.WeekDefinitionId.HasValue)
{
query = query.Where(x => x.WeekDefinitionId == request.WeekDefinitionId.Value);
}
if (request.OnlyActive.HasValue && request.OnlyActive.Value)
{
query = query.Where(x => !x.IsExpired);
}
// فیلتر بر اساس پکیج
if (request.PackageId.HasValue && request.PackageId.Value > 0)
{
query = query.Where(x => x.PackageId == request.PackageId.Value);
}
// مرتب‌سازی بر اساس WeekDefinitionId (نزولی = جدیدترین اول)
query = query.ApplyOrder(sortBy: request.SortBy ?? "-WeekDefinitionId");
var meta = await query.GetMetaData(request.PaginationState, cancellationToken);
var models = await query
.PaginatedListAsync(paginationState: request.PaginationState)
.Select(x => new GetUserWeeklyBalancesResponseModel
{
Id = x.Id,
UserId = x.UserId,
UserFullName = x.User != null ? $"{x.User.FirstName} {x.User.LastName}".Trim() : "",
WeekDefinitionId = x.WeekDefinitionId,
WeekDisplayName = x.WeekDefinition != null ? x.WeekDefinition.DisplayName : "",
LeftLegNewMembers = x.LeftLegNewMembers,
LeftLegCarryover = x.LeftLegCarryover,
LeftLegTotal = x.LeftLegTotal,
RightLegNewMembers = x.RightLegNewMembers,
RightLegCarryover = x.RightLegCarryover,
RightLegTotal = x.RightLegTotal,
TotalBalances = x.TotalBalances,
WeeklyPoolContribution = x.WeeklyPoolContribution,
CalculatedAt = x.CalculatedAt,
IsExpired = x.IsExpired,
Created = x.Created,
PackageId = x.PackageId,
PackageTitle = x.Package != null ? x.Package.Title : ""
})
var rows = await _context.Database
.SqlQuery<GetUserWeeklyBalancesResponseModel>(
$"""
EXEC [CMS].[sp_GetUserWeeklyBalances]
@UserId = {userId},
@WeekDefinitionId = {weekDefinitionId},
@PackageId = {packageId},
@OnlyActive = {onlyActive},
@SortDescending = {sortDescending},
@PageNumber = {pageNumber},
@PageSize = {pageSize}
""")
.ToListAsync(cancellationToken);
var totalCount = rows.Count > 0 ? rows[0].TotalCount : 0;
var totalPageCount = (int)Math.Ceiling(totalCount / (double)pageSize);
var meta = new MetaData
{
CurrentPage = pageNumber,
PageSize = pageSize,
TotalCount = totalCount,
TotalPage = totalPageCount,
HasNext = pageNumber < totalPageCount,
HasPrevious = pageNumber > 1
};
return new GetUserWeeklyBalancesResponseDto
{
MetaData = meta,
Models = models
Models = rows
};
}
}
@@ -33,4 +33,7 @@ public class GetUserWeeklyBalancesResponseModel
// Package info
public long PackageId { get; set; }
public string PackageTitle { get; set; } = string.Empty;
// نتیجه COUNT(*) OVER() از SP — فقط در خواندن از SP پر می‌شود
public int TotalCount { get; set; }
}
@@ -56,5 +56,9 @@ public class NetworkWeeklyBalanceConfiguration : IEntityTypeConfiguration<Networ
// Index برای IsExpired
builder.HasIndex(e => e.IsExpired)
.HasDatabaseName("IX_NetworkWeeklyBalance_IsExpired");
// Index برای PackageId — برای فیلتر در sp_GetUserWeeklyBalances
builder.HasIndex(e => e.PackageId)
.HasDatabaseName("IX_NetworkWeeklyBalance_PackageId");
}
}
@@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace CMSMicroservice.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddNetworkWeeklyBalance_PackageIdIndex : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameIndex(
name: "IX_NetworkWeeklyBalances_PackageId",
schema: "CMS",
table: "NetworkWeeklyBalances",
newName: "IX_NetworkWeeklyBalance_PackageId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameIndex(
name: "IX_NetworkWeeklyBalance_PackageId",
schema: "CMS",
table: "NetworkWeeklyBalances",
newName: "IX_NetworkWeeklyBalances_PackageId");
}
}
}
@@ -2478,7 +2478,8 @@ namespace CMSMicroservice.Infrastructure.Persistence.Migrations
b.HasIndex("IsExpired")
.HasDatabaseName("IX_NetworkWeeklyBalance_IsExpired");
b.HasIndex("PackageId");
b.HasIndex("PackageId")
.HasDatabaseName("IX_NetworkWeeklyBalance_PackageId");
b.HasIndex("WeekDefinitionId")
.HasDatabaseName("IX_NetworkWeeklyBalance_WeekDefinitionId");
@@ -0,0 +1,56 @@
-- =============================================
-- Stored Procedure: sp_GetUserWeeklyBalances
-- Description: دریافت تعادل‌های هفتگی با صفحه‌بندی و فیلترهای مختلف
-- Author: System
-- Created: 2026-05-04
-- =============================================
CREATE OR ALTER PROCEDURE [CMS].[sp_GetUserWeeklyBalances]
@UserId BIGINT = NULL,
@WeekDefinitionId BIGINT = NULL,
@PackageId BIGINT = NULL,
@OnlyActive BIT = 0,
@SortDescending BIT = 1, -- 1 = نزولی (جدیدترین اول)، 0 = صعودی
@PageNumber INT = 1,
@PageSize INT = 10
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Skip INT = @PageSize * (@PageNumber - 1);
SELECT
n.Id,
n.UserId,
LTRIM(RTRIM(ISNULL(u.FirstName, '') + ' ' + ISNULL(u.LastName, ''))) AS UserFullName,
n.WeekDefinitionId,
ISNULL(wd.DisplayName, '') AS WeekDisplayName,
n.LeftLegNewMembers,
n.LeftLegCarryover,
n.LeftLegTotal,
n.RightLegNewMembers,
n.RightLegCarryover,
n.RightLegTotal,
n.TotalBalances,
n.WeeklyPoolContribution,
n.CalculatedAt,
n.IsExpired,
n.Created,
n.PackageId,
ISNULL(p.Title, '') AS PackageTitle,
COUNT(*) OVER() AS TotalCount
FROM [CMS].[NetworkWeeklyBalances] n
LEFT JOIN [CMS].[Users] u ON u.Id = n.UserId
LEFT JOIN [CMS].[WeekDefinitions] wd ON wd.Id = n.WeekDefinitionId
LEFT JOIN [CMS].[Packages] p ON p.Id = n.PackageId
WHERE n.IsDeleted = 0
AND (@UserId IS NULL OR n.UserId = @UserId)
AND (@WeekDefinitionId IS NULL OR n.WeekDefinitionId = @WeekDefinitionId)
AND (@PackageId IS NULL OR n.PackageId = @PackageId)
AND (@OnlyActive = 0 OR n.IsExpired = 0)
ORDER BY
CASE WHEN @SortDescending = 1 THEN n.WeekDefinitionId END DESC,
CASE WHEN @SortDescending = 0 THEN n.WeekDefinitionId END ASC
OFFSET @Skip ROWS
FETCH NEXT @PageSize ROWS ONLY;
END;