【问题标题】:mapstruct update mapping one-to-many relationship by merging child dto with existing child entitiesmapstruct 通过将子 dto 与现有子实体合并来更新映射一对多关系
【发布时间】:2018-04-27 21:02:45
【问题描述】:

我有两个具有一对多关系的实体,如下所示:

public class ParentEntity {

   private Long id;
   private String name;
   private List<ChildEntity> children;

   //getters/setters

}

public class ChildEntity {

    private Long id;
    private String name;
    private ParentEntity myParent;

    private String notMappedField1;
    private Long notMappedField2;

    //getters/setters

}

还有 DTO

public class ParentDTO {

       private Long id;
       private String name;
       private List<ChildDto> children;

       //getters/setters

    }

    public class ChildDto {

        private Long id;
        private String name;
        private ParentDto myParent;

        //getters/setters

    }

使用 Mapstruct 注释我创建了两个映射器,每个实体一个:

   @Mapper(componentModel = "cdi", uses = {ChildMapper.class})
   public interface ParentMapper {      
       ParentDto toDto(ParentEntity entity);     
       ParentEntity toEntity(ParentDto s);      
       ParentEntity toEntity(ParentDto s, @MappingTarget ParentEntity entity);           
   }

   @Mapper(componentModel = "cdi")
   public interface ChildMapper {

       ChildDto toDto(ChildEntity entity);

       @Mapping(target = "myParent", ignore = true)
       ChildEntity toEntity(ChildDto s);

       @InheritConfiguration
       ChildEntity toEntity(ChildDto s, @MappingTarget ChildEntity entity);

   }

生成的父映射器如下:

@ApplicationScoped
public class ParentMapperImpl implements ParentMapper {

    @Inject
    private ChildMapper childMapper;

    @Override
    public ParentDto toDto(ParentEntity entity) {
        if ( entity == null ) {
            return null;
        }

        ParentDto parentDto = new ParentDto();

        parentDto.setId( entity.getId() );
        parentDto.setName( entity.getName() );
        parentDto.setChildren( childEntityListToChildDtoList( entity.getChildren() ) );

        return parentDto;
    }

    @Override
    public ParentEntity toEntity(ParentDto s) {
        if ( s == null ) {
            return null;
        }

        ParentEntity parentEntity = new ParentEntity();

        parentEntity.setId( s.getId() );
        parentEntity.setName( s.getName() );
        parentEntity.setChildren( childDtoListToChildEntityList( s.getChildren() ) );

        return parentEntity;
    }

    @Override
    public ParentEntity toEntity(ParentDto s, ParentEntity entity) {
        if ( s == null ) {
            return null;
        }

        entity.setId( s.getId() );
        entity.setName( s.getName() );
        if ( entity.getChildren() != null ) {
            List<ChildEntity> list = childDtoListToChildEntityList( s.getChildren() );
            if ( list != null ) {
                entity.getChildren().clear();
                entity.getChildren().addAll( list );
            }
            else {
                entity.setChildren( null );
            }
        }
        else {
            List<ChildEntity> list = childDtoListToChildEntityList( s.getChildren() );
            if ( list != null ) {
                entity.setChildren( list );
            }
        }

        return entity;
    }

    protected List<ChildDto> childEntityListToChildDtoList(List<ChildEntity> list) {
        if ( list == null ) {
            return null;
        }

        List<ChildDto> list1 = new ArrayList<ChildDto>( list.size() );
        for ( ChildEntity childEntity : list ) {
            list1.add( childMapper.toDto( childEntity ) );
        }

        return list1;
    }

    protected List<ChildEntity> childDtoListToChildEntityList(List<ChildDto> list) {
        if ( list == null ) {
            return null;
        }

        List<ChildEntity> list1 = new ArrayList<ChildEntity>( list.size() );
        for ( ChildDto childDto : list ) {
            list1.add( childMapper.toEntity( childDto ) );
        }

        return list1;
    }
}

但是当ParentMapper.toEntity(ParentDto s, ParentEntity entity) 被调用时, 在子映射器上称为ChildMapper.toEntity(ChildDto s)

相反,我希望调用以下子映射器方法ChildMapper.toEntity(ChildDto s, ChildEntity entity), 合并现有的子实体(假设我们在 Dto 中不存在且我们不想丢失的子实体)。
期望的结果如下所示,或类似的结果:

@ApplicationScoped
public class ParentMapperImpl implements ParentMapper {

      ...

      @Override
      public ParentEntity toEntity(ParentDto s, ParentEntity entity) {
          if (s == null) {
              return null;
          }

          entity.setId(s.getId());
          entity.setName(s.getName());
          if (entity.getChildren() != null) {
              List<ChildEntity> list = childDtoListToChildEntityList(s.getChildren(), entity.getChildren());
              if (list != null) {
                  entity.getChildren().clear();
                  entity.getChildren().addAll(list);
              } else {
                  entity.setChildren(null);
              }
          } else {
              List<ChildEntity> list = childDtoListToChildEntityList(s.getChildren());
              if (list != null) {
                  entity.setChildren(list);
              }
          }

          return entity;
      }

      ...

      protected List<ChildEntity> childDtoListToChildEntityList(List<ChildDto> list, List<ChildEntity> entities) {
          if (list == null) {
              return null;
          }


          final List<ChildEntity> list1 = new ArrayList<ChildEntity>(list.size());
          for (ChildEntity entity : entities) {
              Optional<ChildEntity> optional = findEntity(entity.getId(), list);
              if (optional.isPresent()) {
                  list1.add(childMapper.toEntity(optional.get(), entity));
              }
          }

          list1.addAll(
                  list.stream()
                          .filter(dto -> dto.getId() == null)
                          .map(dto -> childMapper.toEntity(dto))
                          .collect(Collectors.toList())
          );


          return list1;
      }

      private Optional<ChildEntity> findEntity(Long id, List<ChildDto> list) {
          return list.stream().filter(dto -> dto.getId().equals(id)).findAny();
      }

}          

【问题讨论】:

    标签: java mapping mapstruct


    【解决方案1】:

    我的 porpouse 是通过合并现有的子实体来执行一对多实体关系的更新,假设我们在 Dto 中不存在我们不想丢失的子实体上的其他字段.

    我有两个具有一对多关系的实体,如下所示:

    public class ParentEntity {
    
       private Long id;
       private String name;
       private List<ChildEntity> children;
    
       //getters/setters
    
    }
    
    public class ChildEntity {
    
        private Long id;
        private String name;
        private ParentEntity myParent;
    
        private String notMappedField1;
        private Long notMappedField2;
    
        //getters/setters
    
    }
    

    还有 DTO

    public class ParentDTO {
    
           private Long id;
           private String name;
           private List<ChildDto> children;
    
           //getters/setters
    
        }
    
        public class ChildDto {
    
            private Long id;
            private String name;
            private ParentDto myParent;
    
            //getters/setters
    
        }
    

    使用 Mapstruct 注释我创建了两个映射器,每个实体一个:

       @Mapper(componentModel = "cdi", uses = {ChildMapper.class})
       public interface ParentMapper {      
           ParentDto toDto(ParentEntity entity);     
           ParentEntity toEntity(ParentDto s);      
           ParentEntity toEntity(ParentDto s, @MappingTarget ParentEntity entity);           
       }
    
       @Mapper(componentModel = "cdi")
       public interface ChildMapper {
    
           ChildDto toDto(ChildEntity entity);
    
           @Mapping(target = "myParent", ignore = true)
           ChildEntity toEntity(ChildDto s);
    
           @InheritConfiguration
           ChildEntity toEntity(ChildDto s, @MappingTarget ChildEntity entity);
    
       }
    

    生成的父映射器如下:

    @ApplicationScoped
    public class ParentMapperImpl implements ParentMapper {
    
        @Inject
        private ChildMapper childMapper;
    
        @Override
        public ParentDto toDto(ParentEntity entity) {
            if ( entity == null ) {
                return null;
            }
    
            ParentDto parentDto = new ParentDto();
    
            parentDto.setId( entity.getId() );
            parentDto.setName( entity.getName() );
            parentDto.setChildren( childEntityListToChildDtoList( entity.getChildren() ) );
    
            return parentDto;
        }
    
        @Override
        public ParentEntity toEntity(ParentDto s) {
            if ( s == null ) {
                return null;
            }
    
            ParentEntity parentEntity = new ParentEntity();
    
            parentEntity.setId( s.getId() );
            parentEntity.setName( s.getName() );
            parentEntity.setChildren( childDtoListToChildEntityList( s.getChildren() ) );
    
            return parentEntity;
        }
    
        @Override
        public ParentEntity toEntity(ParentDto s, ParentEntity entity) {
            if ( s == null ) {
                return null;
            }
    
            entity.setId( s.getId() );
            entity.setName( s.getName() );
            if ( entity.getChildren() != null ) {
                List<ChildEntity> list = childDtoListToChildEntityList( s.getChildren() );
                if ( list != null ) {
                    entity.getChildren().clear();
                    entity.getChildren().addAll( list );
                }
                else {
                    entity.setChildren( null );
                }
            }
            else {
                List<ChildEntity> list = childDtoListToChildEntityList( s.getChildren() );
                if ( list != null ) {
                    entity.setChildren( list );
                }
            }
    
            return entity;
        }
    
        protected List<ChildDto> childEntityListToChildDtoList(List<ChildEntity> list) {
            if ( list == null ) {
                return null;
            }
    
            List<ChildDto> list1 = new ArrayList<ChildDto>( list.size() );
            for ( ChildEntity childEntity : list ) {
                list1.add( childMapper.toDto( childEntity ) );
            }
    
            return list1;
        }
    
        protected List<ChildEntity> childDtoListToChildEntityList(List<ChildDto> list) {
            if ( list == null ) {
                return null;
            }
    
            List<ChildEntity> list1 = new ArrayList<ChildEntity>( list.size() );
            for ( ChildDto childDto : list ) {
                list1.add( childMapper.toEntity( childDto ) );
            }
    
            return list1;
        }
    }
    

    我想到的第一个解决方案是通过合并子 dto 列表和子实体列表来执行子实体列表的更新,所以我认为当调用 ParentMapper.toEntity(ParentDto s, ParentEntity entity) 时,子映射器方法 @必须调用 987654326@ 来合并现有的子实体,而不是这个 ChildMapper.toEntity(ChildDto s)
    所以结果可能是以下,或等价的:

    @ApplicationScoped
    public class ParentMapperImpl implements ParentMapper {
    
          ...
    
          @Override
          public ParentEntity toEntity(ParentDto s, ParentEntity entity) {
              if (s == null) {
                  return null;
              }
    
              entity.setId(s.getId());
              entity.setName(s.getName());
              if (entity.getChildren() != null) {
                  List<ChildEntity> list = childDtoListToChildEntityList(s.getChildren(), entity.getChildren());
                  if (list != null) {
                      entity.getChildren().clear();
                      entity.getChildren().addAll(list);
                  } else {
                      entity.setChildren(null);
                  }
              } else {
                  List<ChildEntity> list = childDtoListToChildEntityList(s.getChildren());
                  if (list != null) {
                      entity.setChildren(list);
                  }
              }
    
              return entity;
          }
    
          ...
    
          protected List<ChildEntity> childDtoListToChildEntityList(List<ChildDto> list, List<ChildEntity> entities) {
              if (list == null) {
                  return null;
              }
    
    
              final List<ChildEntity> list1 = new ArrayList<ChildEntity>(list.size());
              for (ChildEntity entity : entities) {
                  Optional<ChildEntity> optional = findEntity(entity.getId(), list);
                  if (optional.isPresent()) {
                      list1.add(childMapper.toEntity(optional.get(), entity));
                  }
              }
    
              list1.addAll(
                      list.stream()
                              .filter(dto -> dto.getId() == null)
                              .map(dto -> childMapper.toEntity(dto))
                              .collect(Collectors.toList())
              );
    
    
              return list1;
          }
    
          private Optional<ChildEntity> findEntity(Long id, List<ChildDto> list) {
              return list.stream().filter(dto -> dto.getId().equals(id)).findAny();
          }
    
    }          
    

    这对 Mapstruct 可行吗? 有没有另一种方法来更新与 Mapstruct 的子关系?

    【讨论】:

    • 这不是和你问的有点不同吗?您要求更新ChildEntity 的集合。这个答案是关于对象工厂的。 (也许我误解了这个问题)
    • 如标题所述,我的海豚是合并子实体,我想到的第一个解决方案是合并子实体列表,也许我提出的解决方案具有误导性,实际上我会是导致相同结果的东西,我编辑了这个问题。对不起。
    【解决方案2】:

    目前这是不可能的。这已经是一个悬而未决的问题。看看487

    执行 2 个列表的合并并非易事。它要求 MapStruct 知道如何生成该 find 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-29
      • 2017-09-17
      • 2011-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-14
      相关资源
      最近更新 更多