使用AutoMapper来展平嵌套对象的更好方法是什么?

Joh*_*ohn 23 c# nested flatten automapper

我一直在将域对象展平为DTO,如下例所示:

public class Root
{
    public string AParentProperty { get; set; }
    public Nested TheNestedClass { get; set; }
}

public class Nested
{
    public string ANestedProperty { get; set; }
}

public class Flattened
{
    public string AParentProperty { get; set; }
    public string ANestedProperty { get; set; }
}

// I put the equivalent of the following in a profile, configured at application start
// as suggested by others:

Mapper.CreateMap<Root, Flattened>()
      .ForMember
       (
          dest => dest.ANestedProperty
          , opt => opt.MapFrom(src => src.TheNestedClass.ANestedProperty)
       );

// This is in my controller:
Flattened myFlattened = Mapper.Map<Root, Flattened>(myRoot);
Run Code Online (Sandbox Code Playgroud)

我已经看了很多例子,到目前为止,这似乎是扁平嵌套层次结构的方法.但是,如果子对象具有许多属性,则此方法不会节省太多编码.

我找到了这个例子:

http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx

但它需要Map()函数所需的映射对象的实例,根据我的理解,它不适用于配置文件.

我是AutoMapper的新手,所以我想知道是否有更好的方法来做到这一点.

Jag*_*Jag 14

在最新版本的AutoMapper中,您可以使用命名约定来避免多个.ForMember语句.

在您的示例中,如果您将Flattened类更新为:

public class Flattened
{
    public string AParentProperty { get; set; }
    public string TheNestedClassANestedProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您可以避免使用ForMember语句:

Mapper.CreateMap<Root, Flattened>();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,Automapper将(根据惯例)映射Root.TheNestedClass.ANestedPropertyFlattened.TheNestedClassANestedProperty.当你使用真正的班级名字时,它看起来不那么难看,老实说!

  • 根据Automapper的使用命名我的视图模型属性不是我想做的事情.我很欣赏答案,但解决方案的副作用会让我在原始问题中使用该技术. (7认同)

Lee*_*des 13

我更喜欢避免使用旧的静态方法并这样做。

将我们的映射定义放入Profile 中。我们首先映射 Root,然后应用 Nested 的映射。注意Context的使用。

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Root, Flattened>()
            .AfterMap((src, dest, context) => context.Mapper.Map(src.TheNestedClass, dest));
        CreateMap<Nested, Flattened>();
    }
}
Run Code Online (Sandbox Code Playgroud)

定义从RootFlattenedNestedFlatterned的映射的优点是您可以保留对属性映射的完全控制,例如目标属性名称是否不同或您想要应用转换等。

XUnit 测试:

[Fact]
public void Mapping_root_to_flattened_should_include_nested_properties()
{
    // ARRANGE
    var myRoot = new Root
    {
        AParentProperty = "my AParentProperty",
        TheNestedClass = new Nested
        {
            ANestedProperty = "my ANestedProperty"
        }
    };

    // Manually create the mapper using the Profile
    var mapper = new MapperConfiguration(cfg => cfg.AddProfile(new MappingProfile())).CreateMapper();

    // ACT
    var myFlattened = mapper.Map<Root, Flattened>(myRoot);

    // ASSERT
    Assert.Equal(myRoot.AParentProperty, myFlattened.AParentProperty);
    Assert.Equal(myRoot.TheNestedClass.ANestedProperty, myFlattened.ANestedProperty);
}
Run Code Online (Sandbox Code Playgroud)

通过将 AutoMapper 的serviceCollection.AddAutoMapper()AutoMapper.Extensions.Microsoft.DependencyInjection nuget 包添加到您的启动,配置文件将被自动选取,您可以简单地将IMapper注入到应用映射的任何位置。


Ale*_*x M 5

2个可能的解决方案:

Mapper.CreateMap<Nested, Flattened>()
    .ForMember(s=>s.AParentProperty, o=>o.Ignore());
Mapper.CreateMap<Root, Flattened>()
    .ForMember(d => d.ANestedProperty, o => o.MapFrom(s => s.TheNestedClass));
Run Code Online (Sandbox Code Playgroud)

另一种方法如下,但它不会通过Mapper.AssertConfigurationIsValid().

Mapper.CreateMap<Nested, Flattened>()
//.ForMember map your properties here
Mapper.CreateMap<Root, Flattened>()
//.ForMember... map you properties here
.AfterMap((s, d) => Mapper.Map(s.TheNestedClass, d));
Run Code Online (Sandbox Code Playgroud)

  • 如果嵌套类中有很多字段,不知道如何解决问题?如果Flattened对象中有多个属性应该从嵌套对象映射,则OP希望避免添加多个"For destination Member"语句. (5认同)