# 🔧 Mapster - مشکلات رایج و راه‌حل‌ها

> **آخرین بروزرسانی**: ۷ دی ۱۴۰۴  
> **نسخه Mapster**: 7.4.0

---

## 📋 فهرست مشکلات

1. [Protobuf Int64Value Mapping](#1-protobuf-int64value-mapping)
2. [MediatR Unit to Empty](#2-mediatr-unit-to-empty)
3. [Repeated Fields (List) Mapping](#3-repeated-fields-list-mapping)
4. [Property Name Mismatch](#4-property-name-mismatch)
5. [Nullable Types](#5-nullable-types)

---

## 1. Protobuf Int64Value Mapping

### مشکل
فیلدهای `google.protobuf.Int64Value` (یا `StringValue`, `BoolValue` و غیره) که wrapper types هستند، در mapping مستقیم کار نمی‌کنند.

### نشانه‌ها
- مقدار همیشه `0` یا `null` می‌شود
- Value در client ست شده ولی در server نادرست دریافت می‌شود

### Proto:
```protobuf
import "google/protobuf/wrappers.proto";

message GetMyWeeklyBalancesRequest {
    google.protobuf.Int64Value week_definition_id = 3;
}
```

### ❌ کد اشتباه:
```csharp
config.NewConfig<GetMyWeeklyBalancesRequest, GetMyWeeklyBalancesQuery>()
    .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId);  // WRONG!
```

### ✅ کد صحیح:
```csharp
config.NewConfig<GetMyWeeklyBalancesRequest, GetMyWeeklyBalancesQuery>()
    .Map(dest => dest.WeekDefinitionId, 
         src => src.WeekDefinitionId != null ? src.WeekDefinitionId.Value : null);
```

### توضیح
`Int64Value` یک class wrapper است نه primitive type. باید `.Value` را extract کنید.

---

## 2. MediatR Unit to Empty

### مشکل
`MediatR.Unit` نمی‌تواند به `google.protobuf.WellKnownTypes.Empty` map شود.

### نشانه‌ها
- Exception: `No mapping found for MediatR.Unit`
- gRPC call با void return کار نمی‌کند

### ❌ کد اشتباه:
```csharp
// No mapping defined - will fail at runtime
return await _mediator.Send(command).Adapt<Empty>();
```

### ✅ راه‌حل:
```csharp
// در GeneralMapping.cs یا هر Profile
config.NewConfig<MediatR.Unit, Google.Protobuf.WellKnownTypes.Empty>()
    .MapWith(_ => new Google.Protobuf.WellKnownTypes.Empty());
```

### محل فایل:
`BackOffice.BFF.WebApi/Common/Mappings/GeneralMapping.cs`

---

## 3. Repeated Fields (List) Mapping

### مشکل
فیلدهای `repeated` در protobuf به property `RepeatedField<T>` تبدیل می‌شوند که `add-only` هستند.

### نشانه‌ها
- لیست همیشه خالی
- Exception: `Cannot set RepeatedField`

### Proto:
```protobuf
message GetAllAppVersionsResponse {
    repeated AppVersionItem items = 1;
}
```

### ❌ کد اشتباه:
```csharp
config.NewConfig<List<AppVersionItemDto>, GetAllAppVersionsResponse>()
    .Map(dest => dest.Items, src => src);  // WRONG - Items is read-only
```

### ✅ کد صحیح:
```csharp
config.NewConfig<List<AppVersionItemDto>, GetAllAppVersionsResponse>()
    .MapWith(src => CreateResponse(src));

private static GetAllAppVersionsResponse CreateResponse(List<AppVersionItemDto> items)
{
    var response = new GetAllAppVersionsResponse();
    foreach (var item in items)
    {
        response.Items.Add(item.Adapt<AppVersionItem>());
    }
    return response;
}
```

---

## 4. Property Name Mismatch

### مشکل
نام property در DTO با نام در proto message یکی نیست.

### نشانه‌ها
- فیلد همیشه `null` یا default value
- Auto-mapping کار نمی‌کند

### مثال:
```protobuf
message MetaData {
    int32 total_page = 2;  // -> TotalPage in C#
}
```

```csharp
public class MetaDataDto
{
    public int TotalPages { get; set; }  // WRONG: should be TotalPage
}
```

### ✅ راه‌حل 1 - اصلاح نام:
```csharp
public class MetaDataDto
{
    public int TotalPage { get; set; }  // Match proto
}
```

### ✅ راه‌حل 2 - Explicit mapping:
```csharp
config.NewConfig<MetaData, MetaDataDto>()
    .Map(dest => dest.TotalPages, src => src.TotalPage);
```

---

## 5. Nullable Types

### مشکل
Nullable types در C# نیاز به handling خاص دارند.

### Proto با nullable:
```protobuf
google.protobuf.Int64Value nullable_id = 1;
```

### ✅ در DTO:
```csharp
public long? NullableId { get; set; }
```

### ✅ Mapping:
```csharp
.Map(dest => dest.NullableId, 
     src => src.NullableId != null ? (long?)src.NullableId.Value : null)
```

---

## 🎯 Best Practices

### 1. همیشه Explicit Mapping برای Complex Types
```csharp
// بهتر است همیشه explicit باشد
config.NewConfig<SourceType, DestType>()
    .Map(dest => dest.Prop1, src => src.Prop1)
    .Map(dest => dest.Prop2, src => src.Prop2);
```

### 2. استفاده از MapWith برای Custom Logic
```csharp
config.NewConfig<Source, Dest>()
    .MapWith(src => new Dest
    {
        // full control
    });
```

### 3. فایل Profile مجزا برای هر Domain
```
Common/Mappings/
├── CommissionProfile.cs
├── NetworkProfile.cs
├── ClubProfile.cs
└── GeneralMapping.cs  // for common types like Unit -> Empty
```

### 4. تست Mapping ها
```csharp
[Fact]
public void Should_Map_Request_To_Query()
{
    // Arrange
    var request = new GetMyWeeklyBalancesRequest { WeekDefinitionId = 7 };
    
    // Act
    var query = request.Adapt<GetMyWeeklyBalancesQuery>();
    
    // Assert
    Assert.Equal(7, query.WeekDefinitionId);
}
```

---

## 📁 فایل‌های Profile در پروژه

| پروژه | مسیر | محتوا |
|-------|------|-------|
| CMS | `WebApi/Common/Mappings/` | CommissionProfile, AppVersionProfile |
| BackOffice.BFF | `Application/Common/Mappings/` | CommissionProfile |
| BackOffice.BFF | `WebApi/Common/Mappings/` | GeneralMapping |
| FrontOffice.BFF | `WebApi/Common/Mappings/` | CommissionProfile |

---

## 🔗 منابع

- [Mapster Documentation](https://github.com/MapsterMapper/Mapster)
- [Protobuf Well-Known Types](https://protobuf.dev/reference/csharp/api-docs/class/google/protobuf/well-known-types/)
- [CHANGELOG-2025-12-27.md](../CHANGELOG-2025-12-27.md) - جزئیات بیشتر
