【问题标题】:Mapping readonly child collection with AutoMapper使用 AutoMapper 映射只读子集合
【发布时间】:2011-11-08 05:45:32
【问题描述】:

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

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

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 持久化的,所以我不得不担心这一点。但是,一次只做一件事。 :)

希望这可以帮助遇到同样问题的其他人,也许正确解决问题的人能够纠正我。

【问题讨论】:

  • +1 你的后地图解决方案救了我。
  • 很酷的解决方案。我会借的:-)
  • AfterMap 的好主意。使用 Source 和 Destination 对象比使用 ResolutionResult 和类似的东西要容易得多!

标签: collections automapper


【解决方案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>();

【讨论】:

    【解决方案2】:

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

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

    然后:

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

    我发现这比有很多忽略声明更容易理解。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-18
      • 1970-01-01
      • 2014-10-28
      • 1970-01-01
      • 2020-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多