Задать вопрос
@mxelgin

Как в Automapper можно отследить на каком уровне вложенности маппится dto?

Есть некие созависимые сущности

from export
inner join nomenklatura
inner join seller

from export
inner join seller


На выходе получаю json любого уровня вложенности в разрезе любой сущности

если хочу получить json до уровня seller отправляю
/export?expand=nomenklatura.seller
/export?expand=seller
/nomenklatura?expand=seller

Для маппинга сущностей использую Automapper 8
Проблема в том что в автомапере, dto не знает на каком уровне вложенности она находится поэтому я не могу правильно собрать json

CreateMap<ExportRetail, ExportRetailDto>()
 .ForMember(dest => dest.Export, opt => opt.MapFrom((src, dest, _, ctx) =>
  src.ExportId == null ? null : ExpandHelper.HasExpand(ctx, "nomenklatura", ExpandMatchMode.Contains) 
   ? ctx.Mapper.Map<NomenklaturaDto>(src.Export)
   : new NomenklaturaDto { InternalId = src.ExportId.Value }));

CreateMap<ExportRetail, ExportRetailDto>()
 .ForMember(dest => dest.Seller, opt => opt.MapFrom((src, dest, _, ctx) =>
  ExpandHelper.HasExpand(ctx, "seller", ExpandMatchMode.Contains) 
   ? ctx.Mapper.Map<SellerDto>(src.Seller)
   : new SellerDto { SellerId = src.SellerId }
 ))

CreateMap<Nomenklatura, NomenklaturaDto>()
 .ForMember(dest => dest.Seller, opt => opt.MapFrom((src, dest, _, ctx) =>
  ExpandHelper.HasExpand(ctx, "seller", ExpandMatchMode.Contains) 
   ? ctx.Mapper.Map<SellerDto>(src.Seller)
   : new SellerDto { SellerId = src.SellerId }
 ))


на примере маппера видно что контекст не знает чей SellerDto.
Или пришел через NomenklaturaDto
/nomenklatura?expand=seller
Или пришел через ExportRetailDto->NomenklaturaDto
/export?expand=nomenklatura.seller
Или пришел через ExportRetailDto
/export?expand=seller

как в автомаппере можно отследить какой уровень вложенности у dto чтобы можно было управлять через expand маппингом?
  • Вопрос задан
  • 80 просмотров
Подписаться Средний Комментировать
Пригласить эксперта
Ответы на вопрос 1
@mxelgin Автор вопроса
сжатый ответ:

CreateMap<ExportRetail, ExportRetailDto>()
                .ForMember(dest => dest.ExportRetailNomenklatura, opt => opt.MapFrom((src, dest, _, ctx) =>
                    ExpandHelper.MapWithDepthControl(src, ctx, (source, depth) =>
                        src.ExportRetailNomenklaturaId == null ? null : ExpandHelper.HasExpand(ctx, "nomenklatura", depth)
                            ? ctx.Mapper.Map<NomenklaturaDto>(src.ExportRetailNomenklatura)
                            : new NomenklaturaDto { InternalId = src.ExportRetailNomenklaturaId.Value })))


public enum ExpandMatchMode
    {
        Exact,
        StartsWith,
        EndsWith,
        Contains
    }
    public static class ExpandHelper
    {
        public static bool HasExpand(ResolutionContext ctx, string pattern, int depth = 0)
        {
            return ctx.Items.TryGetValue("expand", out var obj) &&
                obj is string[] expandArray &&
                expandArray.Any(expandItem =>
                {
                    var segments = expandItem.Split('.');
                    return depth >= 0 &&
                           depth < segments.Length &&
                           segments[depth].Equals(pattern, StringComparison.OrdinalIgnoreCase);
                });
        }

        public static TResult MapWithDepthControl<TSource, TResult>(
            TSource source,
            ResolutionContext ctx,
            Func<TSource, int, TResult> mappingFunc)
        {
            int currentDepth = GetOrInitializeDepth(ctx);

            // Увеличиваем глубину для вложенных вызовов
            ctx.Items["TypeDepth"] = currentDepth + 1;

            try
            {
                return mappingFunc(source, currentDepth);
            }
            finally
            {
                // Восстанавливаем оригинальную глубину
                ctx.Items["TypeDepth"] = currentDepth;
            }
        }

        private static int GetOrInitializeDepth(ResolutionContext ctx)
        {
            if (!ctx.Items.TryGetValue("TypeDepth", out var depthObj))
            {
                depthObj = 0;
                ctx.Items["TypeDepth"] = depthObj;
            }
            return (int)depthObj;
        }
    }
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы