Десериализация в автомаппере

Есть код:

        CreateMap<Mnemoelement, MnemoelementDTO>()
            .ForMember(nameof(MnemoelementDTO.Settings), opt => opt.MapFrom(me => JsonConvert.DeserializeObject<__type__>(me.Settings)));

__type__ - варьируется в зависсимости от свойства me.Type (string)

Например если me.Type == "LINE", то десериаллизоваться должно в тип LineSettings, если me.Type == "CIRCLE", то десериаллизоваться должно в тип CircleSettings.

Если во внутрь MapFrom как-то вставить switch, то это поможет, только вот как?

Как можно это реализовать?


Ответы (1 шт):

Автор решения: Виталий Шебаниц

Чтобы при мапинге выполнять какую-то кастомную логику, можно реализовать свой ResolverMember например так:

    public class ResolverMnemoelement : IValueResolver<Mnemoelement, MnemoelementDTO, ISettings>
    {

        ISettings IValueResolver<Mnemoelement, MnemoelementDTO, ISettings>.Resolve(Mnemoelement source, MnemoelementDTO destination, ISettings destMember, ResolutionContext context)
        {
            ISettings result = null;
            switch (source.Type)
            {
                case "LINE":
                    {
                        result = JsonConvert.DeserializeObject<LineSettings>(source.Settings);
                        break;
                    }
                case "CIRCLE":
                    {
                        result = JsonConvert.DeserializeObject<CircleSettings>(source.Settings);
                        break;
                    }
            }
            return result;
        }
    }

И потом так использовать:

      CreateMap<Mnemoelement, MnemoelementDTO>()
            .ForMember(meDTO => meDTO.LinkType, opt => opt.MapFrom(me => Enum.Parse(typeof(EMnemoelementLinkType), me.LinkType)))
            .ForMember(meDTO => meDTO.Type, opt => opt.MapFrom(me => Enum.Parse(typeof(EMnemoelementType), me.Type)))
            .ForMember(meDTO => meDTO.Settings, opt => opt.MapFrom(new ResolverMnemoelement()));

Это позволит смапить модели:

/// <summary>
/// Элемент на мнемосхеме
/// </summary>
[Table(name: "mnemoelements", Schema = "public")]
public class Mnemoelement : IEntitySingleId<int>
{
    /// <summary>
    /// Идентификатор
    /// </summary>
    [Key]
    [Column("id")]
    public int Id { get; set; }
    /// <summary>
    /// Тип ссылки
    /// MNEMO | GROUP
    /// </summary>
    [Column("link_type")]
    [MaxLength(15)]
    [Required]
    public string LinkType { get; set; }
    /// <summary>
    /// Идентификатор для LinkType
    /// </summary>
    [Column("identifier")]
    [MaxLength(50)]
    [Required]
    public string Identifier { get; set; }
    /// <summary>
    /// Тип элемента
    /// "LINE" | "CIRCLE" | "ICON" | "TEXT" | "LINK"
    /// </summary>
    [Column("type")]
    [MaxLength(50)]
    [Required]
    public string Type { get; set; }
    /// <summary>
    /// Настройки для конкретного элемента
    /// </summary>
    [Column("settings")]
    [MaxLength(50)]
    [Required]
    public string Settings { get; set; }
}

И

public class MnemoelementDTO
{
    /// <summary>
    /// Идентификатор
    /// </summary>
    [Display(Name = "Iдентифікатор", ShortName = "#")]
    public int Id { get; set; }
    /// <summary>
    /// Тип ссылки
    /// MNEMO | GROUP
    /// </summary>
    [Display(Name = "Тип посилання")]
    public EMnemoelementLinkType LinkType { get; set; }
    /// <summary>
    /// Идентификатор для LinkType
    /// </summary>
    [Display(Name = "Iдентифікатор")]
    public string Identifier { get; set; }
    /// <summary>
    /// Тип элемента
    /// "LINE" | "CIRCLE" | "ICON" | "TEXT" | "LINK"
    /// </summary>
    [Display(Name = "Тип елементу")]
    public EMnemoelementType Type { get; set; }
    /// <summary>
    /// Настройки для конкретного элемента
    /// </summary>
    [Display(Name = "Налаштування")]
    public ISettings Settings { get; set; }
}

При этом в модели ISettings может быть любая из доступных моделей настроек

public interface ISettings
{

}

public class LineSettings : ISettings
{
    public Tuple<Point, Point> Position { get; set; }
    public string Color { get; set; } = "#ffffff";
    public double Size { get; set; } = 2.0;

    public class Point
    {
        double X { get; set; }
        double Y { get; set; }
        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }
    }
}

public class CircleSettings : ISettings
{
    public Point Position { get; set; }
    public double Radius { get; set; }
    public string Color { get; set; } = "#ffffff";
    public double BorderSize { get; set; } = 1.0;
    public string BorderColor{ get; set; } = "#ffffff";
    public double Size { get; set; } = 2.0;

    public class Point
    {
        double X { get; set; }
        double Y { get; set; }
        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }
    }
}

p.s. Решение было найдено в документации автомапера

→ Ссылка