如何将嵌套引用扁平化为简单目标?

时间:2019-02-07 19:25:47

标签: mapstruct

我在MapStruct中使用spring数据jdbc。 POJO与具有所有“仅限内部”数据(例如代理键,审计信息等)的表结构对齐,而Domain对象是分层的并且仅包含与业务相关的数据。 我必须在特定于表的POJO(平面结构)和带有嵌套对象的Domain对象之间进行映射。如何最好地使用MapStruct 1.2.0做到这一点?

// Pojo for table
public class PersonsRecord {
    @Id
    private Integer surrogateKey; // should not be mapped

    private String loginId;
    private String name;
    private Timestamp memberSince;

    // address columns
    private Integer houseNumber;
    private String addressStreet;
    private String addressCity;
    private String country;

    // getters and setters
}

// Domain object
public class PersonDto {
    private String loginId;
    private String name;
    private Timestamp memberSince;

    private Address address;
}

@Mapper(uses = MapperUtils.class)
public interface PersonMapper {

    PersonDto toPersonDto(PersonRecord person);

    Address toAddress(PersonRecord person);
}

toPersonDto生成的代码将忽略Address,并且不会调用toAddress参考提及的MapStruct方法。可能是因为两种方法都采用相同的输入类型?为toAddress生成的代码看起来不错。只是MapStruct世代不会自动将其连接。

反向映射生成类似。没有自动通话。

是否有一种方法可以使此过程自动化(无需自定义方法或装饰器等)?我在很多地方都有类似的模式。

注意:MapperUtils用于实例化具有不可变字段的DTO。

更新:我使用了Filip的答案,将其从PersonRecord映射到PersonDto,包括Person.Address。对于反向映射,我执行了以下操作:

@Mapper(uses = MapperUtils.class)
public abstract class PersonMapper {
    @Mapping(target = "address", source = "person")
    public abstract PersonDto toPersonDto(PersonRecord person);

    protected abstract Address toAddress(PersonRecord person);

    public abstract PersonRecord toRecord(PersonDto dto);

    public abstract void updateAddress(PersonDto dto, @MappingTarget PersonRecord person);

    @AfterMapping
    protected void updateAddress(PersonDto dto, @MappingTarget PersonRecord record) {
        updateAddress(dto, record);
    }
}

这没有问题。感谢Filip提供的指导。

1 个答案:

答案 0 :(得分:1)

未采用toAddress方法的原因是MapStruct不知道它需要将toPersonDto参数映射到PersonDto.address。您还很可能会收到一条警告,指出地址未映射。

为了进行映射,您需要告诉MapStruct如何映射address。您可以使用@Mapping来完成。这样,您的映射器就会变成

@Mapper(uses = MapperUtils.class)
public interface PersonMapper {

    @Mapper(target = "address", source = "person")
    PersonDto toPersonDto(PersonRecord person);

    Address toAddress(PersonRecord person);
}

更新,我忘了添加如何执行相反的操作。

执行反向映射的一种方法是使用自定义@Mapping批注,您将必须对Address中的每个条目执行此操作。这有点麻烦。有一个开放的MapStruct提取请求,可以更轻松地完成此映射。 PR是mapstruct/mapstruct#1686

另一种方法是使用多源参数映射。看起来像这样:

@Mapper(uses = MapperUtils.class)
public interface PersonRecordMapper {

    default PersonRecord toPersonRecord(PersonDto personDto) {
        if (personDto == null) {
            return null;
        }

        return toPersonRecord(personDto, personDto.getAddress());
    }

    @Mapping(target = "surrogateKey", ignore = true)
    PersonRecord toPersonRecord(PersonDto personDto, Address address);

}

当且仅当@Mapping中的名称属性与Address中的名称属性匹配时,这才可以在没有手册PersonRecord的情况下工作。否则,您仍然需要定义@Mapping