Add validators and services for Product Galleries and Product Tags

- Implemented Create, Delete, Get, and Update validators for Product Galleries.
- Added Create, Delete, Get, and Update validators for Product Tags.
- Created service classes for handling Discount Categories, Discount Orders, Discount Products, Discount Shopping Cart, Product Categories, Product Galleries, and Product Tags.
- Each service class integrates with CQRS for command and query handling.
- Established mapping profiles for Product Galleries.
This commit is contained in:
masoodafar-web
2025-12-04 02:40:49 +03:30
parent 40d54d08fc
commit f0f48118e7
436 changed files with 33159 additions and 2005 deletions
@@ -8,7 +8,7 @@ namespace CMSMicroservice.Infrastructure.Data.Seeding;
/// <summary>
/// Seeder for migrating existing User.ParentId to User.NetworkParentId
/// این Seeder فقط یک بار اجرا می‌شود و داده‌های قدیمی را به ساختار Binary Tree جدید منتقل می‌کند
/// NOTE: ParentId has been removed from User entity, so this seeder is now obsolete
/// </summary>
public class NetworkParentIdMigrationSeeder
{
@@ -25,147 +25,12 @@ public class NetworkParentIdMigrationSeeder
public async Task SeedAsync(CancellationToken cancellationToken = default)
{
_logger.LogInformation("=== Starting ParentId → NetworkParentId Migration ===");
// Step 1: Validation - Check if migration already done
var alreadyMigrated = await _context.Users
.Where(u => u.ParentId != null && u.NetworkParentId != null)
.AnyAsync(cancellationToken);
if (alreadyMigrated)
{
_logger.LogWarning("⚠️ Migration already completed! Skipping...");
return;
}
// Step 2: Find users with ParentId but no NetworkParentId
var usersToMigrate = await _context.Users
.Where(u => u.ParentId != null && u.NetworkParentId == null)
.OrderBy(u => u.Id)
.ToListAsync(cancellationToken);
if (usersToMigrate.Count == 0)
{
_logger.LogInformation("✅ No users to migrate. All done!");
return;
}
_logger.LogInformation($"📊 Found {usersToMigrate.Count} users to migrate");
// Step 3: Group by ParentId to check binary tree constraint
var parentGroups = usersToMigrate.GroupBy(u => u.ParentId);
int migratedCount = 0;
int skippedCount = 0;
foreach (var group in parentGroups)
{
var parentId = group.Key;
var children = group.OrderBy(u => u.Id).ToList(); // ترتیب بر اساس Id
if (children.Count > 2)
{
_logger.LogWarning(
"⚠️ Parent {ParentId} has {Count} children! Binary tree allows max 2. Taking first 2...",
parentId, children.Count);
children = children.Take(2).ToList();
skippedCount += (group.Count() - 2);
}
// Assign NetworkParentId and LegPosition
for (int i = 0; i < children.Count && i < 2; i++)
{
var child = children[i];
child.NetworkParentId = parentId;
child.LegPosition = i == 0 ? NetworkLeg.Left : NetworkLeg.Right;
_logger.LogDebug(
"✅ Migrated User {UserId}: Parent={ParentId}, Leg={Leg}",
child.Id, parentId, child.LegPosition);
migratedCount++;
}
}
// Step 4: Save changes
await _context.SaveChangesAsync(cancellationToken);
_logger.LogInformation(
"✅ Migration Completed! Migrated={Migrated}, Skipped={Skipped}",
migratedCount, skippedCount);
// Step 5: Post-Migration Validation
await ValidateMigrationAsync(cancellationToken);
}
private async Task ValidateMigrationAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("🔍 Validating Migration...");
// Check 1: Orphaned nodes (NetworkParent doesn't exist)
var orphanedUsers = await _context.Users
.Where(u => u.NetworkParentId != null &&
!_context.Users.Any(p => p.Id == u.NetworkParentId))
.Select(u => new { u.Id, u.NetworkParentId })
.ToListAsync(cancellationToken);
if (orphanedUsers.Any())
{
_logger.LogError(
"❌ Found {Count} orphaned users (NetworkParent doesn't exist): {Ids}",
orphanedUsers.Count,
string.Join(", ", orphanedUsers.Select(u => u.Id)));
}
// Check 2: Binary tree violation (more than 2 children per parent)
var parentsWithTooManyChildren = await _context.Users
.Where(u => u.NetworkParentId != null)
.GroupBy(u => u.NetworkParentId)
.Select(g => new { ParentId = g.Key, Count = g.Count() })
.Where(x => x.Count > 2)
.ToListAsync(cancellationToken);
if (parentsWithTooManyChildren.Any())
{
_logger.LogError(
"❌ Binary tree violation! {Count} parents have more than 2 children",
parentsWithTooManyChildren.Count);
foreach (var parent in parentsWithTooManyChildren)
{
_logger.LogError(" Parent {ParentId} has {Count} children", parent.ParentId, parent.Count);
}
}
// Check 3: Statistics
var stats = await _context.Users
.GroupBy(u => 1)
.Select(g => new
{
TotalUsers = g.Count(),
UsersWithNetworkParent = g.Count(u => u.NetworkParentId != null),
LeftChildren = g.Count(u => u.LegPosition == NetworkLeg.Left),
RightChildren = g.Count(u => u.LegPosition == NetworkLeg.Right)
})
.FirstOrDefaultAsync(cancellationToken);
if (stats != null)
{
_logger.LogInformation("📊 Migration Statistics:");
_logger.LogInformation(" Total Users: {Total}", stats.TotalUsers);
_logger.LogInformation(" Users with NetworkParent: {Count}", stats.UsersWithNetworkParent);
_logger.LogInformation(" Left Children: {Count}", stats.LeftChildren);
_logger.LogInformation(" Right Children: {Count}", stats.RightChildren);
}
if (!orphanedUsers.Any() && !parentsWithTooManyChildren.Any())
{
_logger.LogInformation("✅ Validation Passed! Binary tree is intact.");
}
else
{
_logger.LogError("❌ Validation Failed! Please fix issues manually.");
}
_logger.LogInformation("=== NetworkParentIdMigrationSeeder: ParentId Removed ===");
// ParentId has been removed from User entity
// This seeder is no longer necessary
_logger.LogInformation("ParentId field has been removed. Migration is obsolete.");
await Task.CompletedTask;
}
}