使用AutoMapper映射只读子集合

时间:2011-11-08 05:45:32

标签: collections automapper

这不是一个问题,因为我找到了一种方法来做我想要的,但似乎应该有更好的方法来做到这一点。我到处搜索,没找到任何东西。

基本上,我有我认为非常标准的对象模型。

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
{
}

我使用方法将子项添加到集合的原因是为了保持对添加子项时需要处理的业务逻辑的控制。

使用标准映射:

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 个答案:

答案 0 :(得分:1)

我不喜欢在属性getter或setter中使用逻辑,但是如何将setter添加到Parent类的Children属性

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>();

答案 1 :(得分:0)

我认为如果你出于良好的业务逻辑原因要保护属性,那么如果AutoMapper在进行映射时绕过它们会很糟糕。在这种情况下,我更喜欢放弃流畅的语法,并将创建逻辑放在自己的方法中,如下所示:

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

然后:

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

我发现这比使用大量忽略声明更容易理解。