Сопоставление дочерних классов с родителем, введенным в конструктор с помощью AutoMapper

У меня есть следующая структура класса:

class SrcChild
{
    public bool SomeProperty { get; set; }
}

class SrcParent
{
    public IEnumerable<SrcChild> Children { get; set; }
}

поэтому SrcParent имеет набор объектов SrcChild.

Теперь я хочу сопоставить экземпляр SrcParent с DstParent. Вот классы назначения:

class DstChild
{
    public bool SomeProperty { get; set; }

    public DstChild(DstParent parent)
    {
        if (parent == null)
            throw new ArgumentNullException();
    }
}

class DstParent
{
    public IEnumerable<DstChild> Children { get; set; }
}

DstParent имеет коллекцию объектов DstChild, которые используют внедрение конструктора для сохранения ссылки на своего родителя.

Используя AutoMapper, я попробовал следующее:

class Program
{
    static void Main(string[] args)
    {
        /* mapping configuration */
        Mapper.CreateMap<SrcChild, DstChild>()
            .ConstructUsing(
                resolutionContext => new DstChild((DstParent)resolutionContext.Parent.DestinationValue));
        Mapper.CreateMap<SrcParent, DstParent>();

        /* source parent object with two children */
        var srcParent = new SrcParent
        {
            Children = new[] { new SrcChild(), new SrcChild() }
        };

        /* throws an exception */
        var dstParent = Mapper.Map<DstParent>(srcParent);

        Console.ReadKey();
    }
}

Основная часть здесь — это конфигурация AutoMapper, где я пытаюсь извлечь ссылку на созданный DstParent из контекста сопоставления. Это не работает ((DstParent)разрешениеContext.Parent.DestinationValue равно null), но, может быть, я здесь совершенно не понимаю?

Еще одна идея, которая у меня была, заключалась в том, чтобы использовать функцию для создания дочерних значений, что-то вроде этого:

class Program
{
    /* Should produce value for DstParent.Children */
    private static IEnumerable<DstChild> MakeChildren(SrcParent src /*, DstParent dstParent */)
    {
        var result = new List<DstChild>();
        // result.Add(new DstChild(dstParent));
        return result;
    }

    static void Main(string[] args)
    {
        /* mapping configuration */
        Mapper.CreateMap<SrcChild, DstChild>();
        Mapper.CreateMap<SrcParent, DstParent>()
            .ForMember(dst => dst.Children,
                opt => opt.MapFrom(src => MakeChildren(src /*, How to obtain a reference to the destination here? */)));

        /* source parent object with two children */
        var srcParent = new SrcParent
        {
            Children = new[] { new SrcChild(), new SrcChild() }
        };

        var dstParent = Mapper.Map<DstParent>(srcParent);

        Console.ReadKey();
    }
}

но я не знаю, как (если вообще возможно) получить ссылку на объект DstParent, созданный Mapper.

У кого-нибудь есть идея, как это сделать, или мне лучше подумать о том, чтобы вообще отказаться от этого дизайна и избавиться от родительской ссылки? Заранее спасибо.


person Piotr    schedule 15.12.2015    source источник


Ответы (1)


Хорошо, решение, которое я нашел, не очень красивое, но оно работает:

class Program
{
    static IEnumerable<DstChild> MakeChildren(IEnumerable<SrcChild> srcChildren, DstParent dstParent)
    {
        var dstChildren = new List<DstChild>();
        foreach (SrcChild child in srcChildren)
        {
            var dstChild = new DstChild(dstParent);
            Mapper.Map(child, dstChild);
            dstChildren.Add(dstChild);
        }
        return dstChildren;
    }

    static void Main(string[] args)
    {
        Mapper.CreateMap<SrcChild, DstChild>();
        Mapper.CreateMap<SrcParent, DstParent>()
            /* Ignore Children property when creating DstParent*/
            .ForMember(dst => dst.Children, opt => opt.Ignore())
            /* After mapping is complete, populate the Children property */
            .AfterMap((srcParent, dstParent) =>
            {
                dstParent.Children = MakeChildren(srcParent.Children, dstParent);
            });

        var source = new SrcParent
        {
            Children = new[]
            {
                new SrcChild() {SomeProperty = true},
                new SrcChild() {SomeProperty = false}
            }
        };

        var destination = Mapper.Map<DstParent>(source);

        Console.ReadKey();
    }
}

У пункта назначения инициализированы дочерние элементы, причем SomeProperty правильно назначен AutoMapper. Пожалуйста, дайте мне знать, если вы найдете более красивое решение.

person Piotr    schedule 15.12.2015