web-dev-qa-db-ja.com

MapStruct:オブジェクトが2つのオブジェクトからマップされる場合の、オブジェクトのマップリスト

私がそのようなマッピングを持っていると仮定します:

@Mapping(source = "parentId", target = "parent.id")
Child map(ChildDto dto, Parent parent);

次に、List ofChildDtoをListof Childにマップする必要がありますが、それらはすべて同じ親を持っています。私はそのようなことをすることを期待しています:

List<Child> map(List<ChildDto> dtoList, Parent parent);

しかし、それは機能しません。それをする機会はありますか?

5
AlexB

Gunnarが提案したように、私は_@AfterMapping_を使用しました。

@AfterMapping public void afterDtoToEntity(final QuestionnaireDTO dto, @MappingTarget final Questionnaire entity) { entity.getQuestions().stream().forEach(question -> question.setQuestionnaire(entity)); }

これにより、すべての質問が同じ質問表エンティティにリンクされていることが確認されました。これは、子のリストを使用して新しい親エンティティを作成する際のJPAエラー_save the transient instance before flushing_を回避するためのソリューションの最後の部分でした。

3
Stephanie

@Gunnarに感謝します。デコレータを使用して実装する方法を見つけました。実装は次のとおりです。

_public class Child {
    int id;
    String name;
}
public class Parent {
    int id;
    String name;
}
public class ChildDto {
    int id;
    String name;
    int parentId;
    String parentName;
}
// getters/settes ommited
_

マッパー

_@Mapper
@DecoratedWith(ChildMapperDecorator.class)
public abstract class ChildMapper {
    public static final ChildMapper INSTANCE = Mappers.getMapper(ChildMapper.class);

    @Mappings({
            @Mapping(target = "parentId", ignore = true),
            @Mapping(target = "parentName", ignore = true)
    })
    @Named("toDto")
    abstract ChildDto map(Child child);

    @Mappings({
            @Mapping(target = "id", ignore = true),
            @Mapping(target = "name", ignore = true),
            @Mapping(target = "parentId", source = "id"),
            @Mapping(target = "parentName", source = "name")
    })
    abstract ChildDto map(@MappingTarget ChildDto dto, Parent parent);

    @IterableMapping(qualifiedByName = "toDto") // won't work without it
    abstract List<ChildDto> map(List<Child> children);

    List<ChildDto> map(List<Child> children, Parent parent) {
        throw new UnsupportedOperationException("Not implemented");
    }
}
_

デコレータ

_public abstract class ChildMapperDecorator extends ChildMapper {
    private final ChildMapper delegate;

    protected ChildMapperDecorator(ChildMapper delegate) {
        this.delegate = delegate;
    }

    @Override
    public List<ChildDto> map(List<Child> children, Parent parent) {
        List<ChildDto> dtoList = delegate.map(children);
        for (ChildDto childDto : dtoList) {
            delegate.map(childDto, parent);
        }
        return dtoList;
    }
}
_

マッパーにはinterfaceではなく_abstract class_を使用します。これは、interfaceの場合、生成メソッドmap(List<Child> children, Parent parent)を除外できず、生成されるコードがコンパイル時に無効です。

2
AlexB

現状では、箱から出してそれは不可能です。デコレータまたはアフターマッピングメソッドを使用して、後で親をすべての子オブジェクトに設定できます。

1
Gunnar