【问题标题】:How to Map an object contains other object with @oneToMany如何使用@oneToMany 映射包含其他对象的对象
【发布时间】:2021-11-22 10:01:32
【问题描述】:

给定如下定义的 Source 类:

class Person{
    private String name;
    private int age;
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "peroson")
    List<Phone> phones
    // getters and setters
}

以及如下定义的电话类:

class Phone{
        private Long id;
        private String phoneNumber;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "person")
        private Person person;
        // getters and setters
    }

和 DTO 对象:

class PersonDTO{
        private String name;
        private int age;
        List<PhoneDTO> phones
        // getters and setters
    }

class PhoneDTO{
            private Long id;
            private String phoneNumber;
            private PersonDTO person;
            // getters and setters
        }

我有一个界面:

@Mapper(uses={PersonMapper.class})
interface PhoneMapper{
    PhoneDTO toDto(Phone source);
    Phone toEntity(PhoneDTO source);
}

 @Mapper(uses={PhoneMapper.class})
    interface PersonMapper{
        PersonDTO toDto(Person source);
        Person toEntity(PersonDTO source);
    }

当我使用PeronMapperPhoneMapper 时,会出现递归调用,因为PersonMapper 使用PhoneMapperPersonMapper 使用PhoneMapper

如何解决?

【问题讨论】:

    标签: java dozer mapstruct


    【解决方案1】:

    有很多方法可以避免递归。

    第一个选项:

    通过在您的一个映射器中显式忽略来避免

    第二个选项:

    使用@Context 并编写您自己的备忘录。在 mapstruct 示例 repo 中有一个示例 mapstruct-mapping-with-cycles

    这个想法是有一个@Context

    public class CycleAvoidingMappingContext {
        private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();
    
        @BeforeMapping
        public <T> T getMappedInstance(Object source, @TargetType Class<T> targetType) {
            return (T) knownInstances.get( source );
        }
    
        @BeforeMapping
        public void storeMappedInstance(Object source, @MappingTarget Object target) {
            knownInstances.put( source, target );
        }
    }
    

    然后将此上下文的实例传递给您的映射器:

    @Mapper(uses={PersonMapper.class})
    interface PhoneMapper{
        PhoneDTO toDto(Phone source, @Context CycleAvoidingContext context);
        Phone toEntity(PhoneDTO source, @Context CycleAvoidingContext context);
    }
    
    @Mapper(uses={PhoneMapper.class})
    interface PersonMapper{
        PersonDTO toDto(Person source, @Context CycleAvoidingContext context);
        Person toEntity(PersonDTO source, @Context CycleAvoidingContext context);
    }
    

    当然CycleAvoidingMappingContext 可以有更多指定的来源,而不仅仅是Object。例如,您可以为PersonPersonDTO 设置一个。如何实现它取决于您。

    编辑:

    当映射器之间存在循环依赖时,唯一的解决方案是使用依赖注入框架。默认 MapStruct Mappers 工厂不支持循环。

    【讨论】:

    • 这个解决方案是针对另一个问题 A -> B -> A 实体这里的问题是 Mapper 实例。 Amapper 调用 Bmapper 但 Bmapper 也使用 Amapper => 递归使用。我有同样的问题,但我不知道如何解决它
    • 你是对的@Sum_Pie。我已经对问题添加了一个编辑以澄清这一点
    • 好吧,其实今天我是这样解决问题的:@Mapper(uses=B_Mapper.class) A_Mapper { } interface B_Mapper{ A_Mapper mapA = Mappers.get(A_Mapper.class) }
    猜你喜欢
    • 2018-08-02
    • 2021-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    相关资源
    最近更新 更多