226 lines
6.2 KiB
Markdown
226 lines
6.2 KiB
Markdown
# 🔄 Migration Guide: ParentId → NetworkParentId
|
|
|
|
## 📋 Overview
|
|
|
|
در سیستم قدیمی، کاربران با استفاده از `User.ParentId` به هم متصل میشدند (Parent-Child relationship).
|
|
سیستم جدید **Network-Club-Commission** از یک **Binary Tree** استفاده میکند که نیاز به:
|
|
- `User.NetworkParentId` (شناسه پدر در شبکه باینری)
|
|
- `User.LegPosition` (Left یا Right)
|
|
|
|
برای اجرای صحیح Worker و محاسبات، **باید** تمام کاربران قدیمی Migrate شوند.
|
|
|
|
---
|
|
|
|
## ⚠️ Critical Issues
|
|
|
|
### مشکل 1: Binary Tree Constraint
|
|
- هر Parent فقط میتواند **2 فرزند** داشته باشد (Left & Right)
|
|
- اگر کاربری در سیستم قدیمی بیشتر از 2 فرزند دارد، Migration فقط **2 فرزند اول** را میگیرد
|
|
|
|
### مشکل 2: Orphaned Nodes
|
|
- اگر `ParentId` اشاره به یک کاربر نامعتبر (حذف شده) باشد، آن User **Orphaned** است
|
|
- Orphaned nodes در Binary Tree نادیده گرفته میشوند
|
|
|
|
---
|
|
|
|
## 🚀 Migration Methods
|
|
|
|
### روش 1: Automatic (Seeder - توصیه میشود)
|
|
|
|
Migration به صورت خودکار در `Program.cs` در حالت **Development** اجرا میشود:
|
|
|
|
```csharp
|
|
// در Program.cs
|
|
var migrationSeeder = new NetworkParentIdMigrationSeeder(dbContext, logger);
|
|
await migrationSeeder.SeedAsync();
|
|
```
|
|
|
|
**مزایا:**
|
|
- ✅ Idempotent (میتوان چندین بار اجرا کرد، فقط یکبار تاثیر میگذارد)
|
|
- ✅ Validation اتوماتیک
|
|
- ✅ Logging کامل
|
|
|
|
**کجا اجرا میشود؟**
|
|
- فقط در **Development** environment
|
|
- هر بار که پروژه Run شود
|
|
|
|
---
|
|
|
|
### روش 2: Manual (Command)
|
|
|
|
اگر نیاز به اجرای دستی دارید:
|
|
|
|
```csharp
|
|
// درخواست از طریق MediatR
|
|
var result = await _mediator.Send(new MigrateNetworkParentIdCommand());
|
|
|
|
if (result.Success)
|
|
{
|
|
Console.WriteLine($"Migrated: {result.MigratedCount}");
|
|
Console.WriteLine($"Skipped: {result.SkippedCount}");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Error: {result.Message}");
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### روش 3: SQL Script
|
|
|
|
برای Production یا اجرای مستقیم روی Database:
|
|
|
|
```bash
|
|
# فایل: CMSMicroservice.Infrastructure/Migrations/Scripts/20250601_MigrateParentIdToNetworkParentId.sql
|
|
```
|
|
|
|
**نکته مهم:**
|
|
قبل از اجرا، **حتماً** بررسی کنید که آیا کاربری بیش از 2 فرزند دارد:
|
|
|
|
```sql
|
|
SELECT
|
|
ParentId,
|
|
COUNT(*) as ChildCount,
|
|
STRING_AGG(CAST(Id AS VARCHAR), ', ') as ChildIds
|
|
FROM Users
|
|
WHERE ParentId IS NOT NULL
|
|
GROUP BY ParentId
|
|
HAVING COUNT(*) > 2;
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Validation After Migration
|
|
|
|
### 1. بررسی تعداد کاربران Migrate شده
|
|
|
|
```csharp
|
|
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();
|
|
```
|
|
|
|
### 2. بررسی Orphaned Nodes
|
|
|
|
```sql
|
|
SELECT Id, NetworkParentId
|
|
FROM Users
|
|
WHERE NetworkParentId IS NOT NULL
|
|
AND NetworkParentId NOT IN (SELECT Id FROM Users);
|
|
```
|
|
|
|
### 3. بررسی Binary Tree Violation
|
|
|
|
```sql
|
|
SELECT NetworkParentId, COUNT(*) as ChildCount
|
|
FROM Users
|
|
WHERE NetworkParentId IS NOT NULL
|
|
GROUP BY NetworkParentId
|
|
HAVING COUNT(*) > 2;
|
|
```
|
|
|
|
---
|
|
|
|
## ⚙️ Algorithm Details
|
|
|
|
### مراحل Migration:
|
|
|
|
1. **Find Users**: یافتن کاربران با `ParentId != NULL` و `NetworkParentId == NULL`
|
|
2. **Group by Parent**: گروهبندی بر اساس ParentId
|
|
3. **Check Constraint**: اگر Parent بیش از 2 فرزند دارد، فقط 2 تا اول را بگیر
|
|
4. **Assign Values**:
|
|
```csharp
|
|
child.NetworkParentId = parentId;
|
|
child.LegPosition = (i == 0) ? NetworkLeg.Left : NetworkLeg.Right;
|
|
```
|
|
5. **Save & Validate**: ذخیره و اعتبارسنجی Binary Tree
|
|
|
|
---
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
### مشکل: Parent has more than 2 children
|
|
|
|
**راه حل:**
|
|
تصمیم دستی بگیرید که کدام 2 فرزند را نگه دارید:
|
|
|
|
```sql
|
|
-- بررسی کنید که کدام Parent مشکل دارد
|
|
SELECT ParentId, COUNT(*) as ChildCount
|
|
FROM Users
|
|
WHERE ParentId = 123
|
|
GROUP BY ParentId;
|
|
|
|
-- لیست فرزندان را ببینید
|
|
SELECT Id, FullName, CreatedAt
|
|
FROM Users
|
|
WHERE ParentId = 123
|
|
ORDER BY CreatedAt;
|
|
|
|
-- دستی NetworkParentId را برای 2 فرزند انتخابی Set کنید
|
|
UPDATE Users
|
|
SET NetworkParentId = 123, LegPosition = 0 -- Left
|
|
WHERE Id = 456;
|
|
|
|
UPDATE Users
|
|
SET NetworkParentId = 123, LegPosition = 1 -- Right
|
|
WHERE Id = 789;
|
|
```
|
|
|
|
---
|
|
|
|
### مشکل: Orphaned Nodes (Parent doesn't exist)
|
|
|
|
**راه حل:**
|
|
ParentId را NULL کنید یا به یک Parent معتبر متصل کنید:
|
|
|
|
```sql
|
|
-- گزینه 1: NULL کردن (Root شدن)
|
|
UPDATE Users
|
|
SET ParentId = NULL, NetworkParentId = NULL
|
|
WHERE ParentId = 999; -- 999 وجود ندارد
|
|
|
|
-- گزینه 2: اتصال به Parent دیگر
|
|
UPDATE Users
|
|
SET ParentId = 1, NetworkParentId = 1
|
|
WHERE ParentId = 999;
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Checklist Before Production
|
|
|
|
- [ ] Migration در Development اجرا شده؟
|
|
- [ ] Validation Errors بررسی شد؟
|
|
- [ ] Orphaned Nodes رفع شدند؟
|
|
- [ ] Binary Tree Violations رفع شدند؟
|
|
- [ ] Backup از Database گرفته شده؟
|
|
- [ ] Migration Script برای Production آماده است؟
|
|
- [ ] Testing کامل انجام شده؟
|
|
|
|
---
|
|
|
|
## 🔗 Related Files
|
|
|
|
- **Seeder**: `CMSMicroservice.Infrastructure/Data/Seeding/NetworkParentIdMigrationSeeder.cs`
|
|
- **Command**: `CMSMicroservice.Application/UserCQ/Commands/MigrateNetworkParentId/`
|
|
- **SQL Script**: `CMSMicroservice.Infrastructure/Migrations/Scripts/20250601_MigrateParentIdToNetworkParentId.sql`
|
|
- **Entity**: `CMSMicroservice.Domain/Entities/User.cs` (خطوط 16, 45, 49)
|
|
|
|
---
|
|
|
|
## 📞 Support
|
|
|
|
اگر مشکل خاصی با Migration پیدا کردید:
|
|
1. Log های Seeder را بررسی کنید
|
|
2. ValidationErrors را چک کنید
|
|
3. SQL Script را به صورت دستی اجرا کنید
|