代码之家  ›  专栏  ›  技术社区  ›  Investigator

使用MapStruct的Spring数据和JPA一对多

  •  2
  • Investigator  · 技术社区  · 8 年前

    我在Config和ConfigHeaders之间有一个一对多的关系。 以下是配置映射器:

    @Mapper(componentModel = "spring", uses = {UserMapper.class, ConfigHeadersMapper.class})
    public interface ConfigMapper extends EntityMapper<ConfigDTO, Config> {
    
        @Mapping(source = "user.id", target = "userId")
        ConfigDTO toDto(Config config);
    
        @Mapping(source = "userId", target = "user")
        @Mapping(target = "messages", ignore = true)
        Config toEntity(ConfigDTO configDTO);
    
        default Config fromId(Long id) {
            if (id == null) {
                return null;
            }
            Config config = new Config();
            config.setId(id);
            return config;
        }
    }
    

    下面是ConfigHeadersMapper:

    @Mapper(componentModel = "spring", uses = {ConfigMapper.class})
    public interface ConfigHeadersMapper extends EntityMapper<ConfigHeadersDTO, ConfigHeaders> {
    
        @Mapping(source = "config.id", target = "configId")
        ConfigHeadersDTO toDto(ConfigHeaders configHeaders);
    
        @Mapping(source = "configId", target = "config")
        ConfigHeaders toEntity(ConfigHeadersDTO configHeadersDTO);
    
        default ConfigHeaders fromId(Long id) {
            if (id == null) {
                return null;
            }
            ConfigHeaders configHeaders = new ConfigHeaders();
            configHeaders.setId(id);
            return configHeaders;
        }
    }
    

    当我尝试保存新实体(Config&ConfigHeaders的ID等于null)时,这段代码:

    final Config config = configMapper.toEntity(configDTO);
    Config newConfig = configRepository.save(config);
    

    保存Config和ConfigHeaders,但ConfigHeaders处的Config\u id(FK)为空。

    所以我尝试了以下代码:

    final Config config = configMapper.toEntity(configDTO);
    config.getHeaders().stream().forEach(header -> header.setConfig(config));
    Config newConfig = configRepository.save(config);
    

    并使用自动生成的父ID(config\u ID)保存子项(ConfigHeaders)。

    你能告诉我MapStruct有什么问题吗? 我对这个工具很陌生,我不相信这是正确的解决方案。我认为前面的代码目前只是一种变通方法。

    实际上,我已经检查了已生成的MapStruct实现代码,并注意到它正确设置了父ID(对于新ID为null),但它没有设置与父实体的向后关系。如何通过MapStruct实现这一点?

    提前谢谢你

    2 回复  |  直到 8 年前
        1
  •  5
  •   Filip    8 年前

    正如您所注意到的,为了让JPA正确执行保存,您需要在 ConfigHeader .

    有两种方法可以实现这一点:

    第一种选择:

    您可以使用 CollectionMappingStrategy#ADDER_PREFERRED (请参阅更多 here ). 为此,您需要添加 Config 类似于:

    public void addHeader(ConfigHeader header) {
        this.headers.add(header);
        header.setConfig(this);
    }
    

    第二种选择:

    您使用 @AfterMapping 在您的 ConfigMapper 并在所有标题上设置配置。

    @AfterMapping
    default void linkHeaders(@MappingTarget Config config) {
        config.getHeaders().stream().forEach(header -> header.setConfig(config));
    }
    

    第三种方案由@sjaak于年提出 https://stackoverflow.com/a/48974119/1115491 :

    您可以使用 @Context 属性,如中所示 mapstruct-jpa-child-parent 实例这与第一个选项具有相同的性能,因为您不必在头上迭代两次。另一个好处是,当您无法向实体添加内容时,可以使用它。

    它看起来像:

    public class ConfigContext {
        private Config config;
        @BeforeMapping
        public void setConfig(@MappingTarget Config config) {
           this.config = config;
        }
    
        @AfterMapping
        public void establishRelation(@MappingTarget ConfigHeader header) {
            header.setConfig( header );
        }
    }
    

    您还需要调整 toEntity 方法,以便它们也包括上下文。

        2
  •  3
  •   Sjaak    8 年前

    您还可以使用@上下文。这也为您提供了使用EntityManager进行操作的可能性。看 here 例如。