Java MapStruct:对象的映射列表,当对象从两个对象映射时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37253541/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:07:00  来源:igfitidea点击:

MapStruct: Map List of objects, when object is mapped from two objects

javamappingmapstruct

提问by AlexB

Assume I have such mapping:

假设我有这样的映射:

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

Now I need to map List of ChildDto to List of Child, but they all have the same parent. I expect to do something like that:

现在我需要将 ChildDto 列表映射到 Child 列表,但它们都具有相同的父级。我希望做这样的事情:

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

But it doesn't working. Is there any chance to do it?

但它不起作用。有机会做到吗?

回答by Gunnar

That's not possible out of the box as things stand. You could use a decorator or after-mapping method to set the parent to all the child objects afterwards.

就目前情况而言,这是不可能开箱即用的。您可以使用装饰器或后映射方法将父对象设置为之后的所有子对象。

回答by AlexB

I found how to implement it with decorators, thanks @Gunnar Here is an implementation:

我找到了如何用装饰器实现它,谢谢@Gunnar 这是一个实现:

Beans

豆子

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

映射器

@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");
    }
}

Decorator

装饰器

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

I use abstract class, not interfacefor mapper, because in case of interfaceyou couldn't exclude for generation method map(List<Child> children, Parent parent), and the code being generated is not valid in compile time.

我使用abstract class, 不interface用于映射器,因为如果interface您无法排除生成方法map(List<Child> children, Parent parent),并且正在生成的代码在编译时无效。

回答by Stephanie

I used an @AfterMappingas suggested by Gunnar:

我使用了@AfterMappingGunnar 的建议:

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

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

This made sure all the questions were linked to the same questionnaire entity. This was the final part of the solution for avoiding the JPA error save the transient instance before flushingon creating a new parent entity with a list of children.

这确保所有问题都链接到同一个问卷实体。这是避免save the transient instance before flushing在创建具有子项列表的新父实体时出现JPA 错误的解决方案的最后一部分。