> For the complete documentation index, see [llms.txt](https://quyvu.gitbook.io/quy/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://quyvu.gitbook.io/quy/v0-bat-dau-phat-trien/publish-your-docs.md).

# Enhancement

Việc coding như "những dòng code đầu tiên..." chỉ giải quyết bài toán trước mắt...

Đến tháng 7/2023, phần mềm của tụi mình đã hoàn thành xong sứ mệnh của nó, 1 phần là bussiness của nó ko đáp ứng được thị trường hiện tại. Dự án chuyển sang version mới. Nhân tiện sang version mới, mình quyết định sẽ bắt đầu enhance lại Mapping engine...

Đầu tiên, mình thay thế việc phải coding như chapter trước bằng việc mỗi `Attribute` phải được định nghĩa với 1 `Request` và `RequestHandler` tương ứng với request đó, xong đó mình sẽ mapping `Attribute` với `Request` đó.

```csharp
// E.g
// Attribute (on Shared project)
public class UserNameOfAttribute : Attribute, IMappableCore
{
    public UserNameOfAttribute(string propertyName) => PropertyName = propertyName;

    public string PropertyName { get; }
}
// Request (on Contract.Identity project)
public record GetMappableUserNamesQuery(List<Guid> Ids) : GetMappableQuery(Ids);

// Handler(on IdentityService project)
public sealed class GetMappableUserNamesHandler(
    ISqlRepository<User> sqlRepository,
    IMapper mapper,
    ILogger logger)
    : EfQueryCollectionHandler<User, GetMappableUserNamesQuery, MappableDataResponse>(sqlRepository,
            mapper, logger)
{
    protected override IQueryListFlowBuilder<User, MappableDataResponse> BuildQueryFlow(
        IQueryListFilter<User, MappableDataResponse> fromFlow,
        GetMappableUserNamesQuery query)
        => fromFlow
            .WithFilter(x => query.Ids.Select(a => new ApplicationUserId(a)).Contains(x.UserId))
            .WithSpecialAction(x => x.Select(a => new MappableDataResponse
                { Id = a.UserId.ToString(), Value = a.Name }))
            .WithSortFieldWhenNotSet(a => a.Id)
            .WithSortedDirectionWhenNotSet(SortedDirection.Ascending);
}
```

Mapping engine:

```csharp
// Creating a storage to link a `Attribute` to a `Request`:
private static readonly Dictionary<Type, Type> QueryStorage = new()
{
    { typeof(DistrictOfAttribute), typeof(GetMappableDistrictsQuery) },
    { typeof(ProvinceOfAttribute), typeof(GetMappableProvincesQuery) },
    { typeof(UserNameOfAttribute), typeof(GetMappableUserNamesQuery) },
    { typeof(UserEmailOfAttribute), typeof(GetMappableEmailsQuery) }
};

// Map engine core:
var allPropertyDatas = GetAllPropertyDatas(okObjectResult).ToList();
var mappableTypeWithIds = GetMappableTypeWithIds(allPropertyDatas);
var allTask = mappableTypeWithIds
    .Select(async x =>
    {
        var attributeType = x.MappableAttributeType;
        if (!QueryStorage.TryGetValue(attributeType, out var queryType)) return;
        var query = Activator.CreateInstance(queryType, x.Ids.ToList());
        if (query is null) return;
        var result = await _sender.Send(query);
        if (result is not CollectionResponse<MappableDataResponse> collectionResponse) return;
        allPropertyDatas.ForEach(propertyData =>
        {
            var value = collectionResponse.Items.FirstOrDefault(a => a.Id == propertyData.Value)?.Value;
            if (value is { }) propertyData.PropertyInfo.SetValue(propertyData.Model, value);
        });
    });
await Task.WhenAll(allTask);
```

Mọi thứ có vẻ ổn hơn 1 chút rồi.

Mình sử dụng `MediatR` để Send request & get response từ các services khác. Như mình đã đề cập ở chapper trước. Mình sử dụng `Masstransit` và `MediatR` kết hợp với nhau để thực hiện  việc request/reply.

Bài toán có vẻ rõ ràng hơn chút rồi... Hehe!

### **Vấn đề gặp phải hiện tại...**

Nhìn code phía trên thì mình thấy có vài vấn đề sau.

1. Mapping engine bị phụ thuộc vào việc dịnh nghĩa `Attribute` và `Request`. Dẫn đến việc khi phát sinh thêm nghiệp vụ lại phải vào để sửq code của **mapping engine.**&#x20;
2. Value dùng để set vào target properties đang là kiểu dữ liệu `string`. Nghĩa là dữ liệu đều convert về hết string. Điều này khiến cho việc mapping data không flexible được về kiểu dữ liệu.
