Отображение только дочерней коллекции с помощью AutoMapper - PullRequest
16 голосов
/ 08 ноября 2011

Это не столько вопрос, сколько я нашел способ сделать то, что я хочу, но, похоже, должен быть лучший способ сделать это.Я искал везде и ничего не нашел.

По сути, у меня есть то, что я считаю очень стандартной объектной моделью.

public class Parent
{
    private readonly IList<Child> _children = new List<Child>();
    public IEnumerable<Child> Children { get { return _children; } }
    public void AddChild(Child child)
    {
        child.Parent = this;
        _children.Add(child);
    }
}

и

public class Child
{
    public Parent Parent { get; set; }
}

(Я упустил свойства, не относящиеся к проблеме, а также проверку и защиту от ошибок для ясности ...)

public class ParentDTO
{
    List<ChildDTO> Children = new List<ChildDTO>();
}

и

public class ChildDTO
{
}

Причина IЯ использую метод для добавления дочерних элементов в коллекцию, чтобы поддерживать контроль над бизнес-логикой, которая должна обрабатываться при добавлении дочернего элемента.

При стандартном отображении:

Mapper.CreateMap<Parent, ParentDTO>();
Mapper.CreateMap<ParentDTO, Parent>();
Mapper.CreateMap<Child, ChildDTO>();
Mapper.CreateMap<ChildDTO, Child>();

Похоже, что работает нормально, исходя из уровня обслуживания.Дочерние объекты объекта домена идеально отображаются в список ChildDTO экземпляров.

Однако при обратном сопоставлении коллекция в доменной модели не задается, поскольку, очевидно, она доступна только для чтения.Кажется, нет никакого способа напрямую установить приватное поле с помощью AutoMapper.Я пробовал различные предложения, найденные здесь и в других частях Интернета.

В конце концов, я придумал следующее сопоставление:

Mapper.CreateMap<ParentDTO, Parent>()
    .ForMember(m => m.Children, o => o.Ignore())
    .AfterMap((s, d) =>
                        {
                            foreach(var c in s.Children)
                                d.AddChild(Mapper.Map<ChildDTO, Child>(c));
                        });

Это работает так, как мне нужно.Тем не менее, я не могу избавиться от ощущения, что должен быть лучший способ, и я не проверял это с существующим родителем, у которого были изменены дети и, возможно, добавлены и удалены, так что я знаю, что это на самом деле еще не правильно.В конечном счете, эта модель предметной области сохраняется с помощью NHibernate, поэтому я должен беспокоиться об этом.Но по одной за раз.:)

Надеюсь, это может помочь кому-то, кто столкнулся с той же проблемой, и, возможно, кто-то, кто решил ее правильно, сможет исправить меня.

Ответы [ 2 ]

2 голосов
/ 17 марта 2018

Мне не нравится иметь логику внутри свойства getter или setter, но как насчет добавления setter в свойство Children класса Parent

public class Parent
{
    private readonly IList<Child> _children = new List<Child>();

    public IEnumerable<Child> Children
    {
        get => _children;
        set => AddChildren(value);
    }

    public void AddChild(Child child)
    {
        child.Parent = this;
        _children.Add(child);
    }

    private void AddChildren(IEnumerable<Child> children)
    {
        _children.Clear();

        foreach (var child in children)
        {
            AddChild(child);
        }
    }
}

И логика AfterMap больше не нужна. Конфигурация отображения будет простой

Mapper.CreateMap<ParentDTO, Parent>();
0 голосов
/ 22 июня 2012

Я думаю, что если вы собираетесь защищать свойства по хорошей бизнес-логике, было бы плохо, если бы AutoMapper обошел их при выполнении своего отображения. В подобных ситуациях я предпочитаю отказаться от свободного синтаксиса и поместить логику создания в свой собственный метод, подобный этому:

private Parent MapParentDTOToParent(ParentDTO source)
{
    var parent = new Parent();
    // Business logic here
    return parent
}

и затем:

Mapper.CreateMap<ParentDTO, Parent>().ConvertUsing(MapParentDTOToParent);

Мне легче следовать, чем иметь множество объявлений игнорирования.

...