将双向实体方法与 Mapstruct 结合使用
Use bidirectional entity methods with Mapstruct
我有双向映射 (@OneToMany Hibernate) 和额外的方法来确保 object 链接。
简单示例:
@Setter
class ParentDto {
List<ChildDto> childList;
}
@Setter
class ChildDto {
String text;
}
@Setter
class Parent {
List<Child> childList;
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
}
@Setter
class Child {
Parent parent;
String text;
}
映射器:
@Mapper(componentModel = "spring")
public interface TestMapper {
Parent toEntity(ParentDto parentDto);
}
生成:
public class TestMapperImpl implements TestMapper {
@Override
public Parent toEntity(ParentDto parentDto) {
if ( parentDto == null ) {
return null;
}
Parent parent = new Parent();
parent.setChildList( childDtoListToChildList( parentDto.getChildList() ) );
return parent;
}
protected Child childDtoToChild(ChildDto childDto) {
if ( childDto == null ) {
return null;
}
Child child = new Child();
child.setText( childDto.getText() );
return child;
}
protected List<Child> childDtoListToChildList(List<ChildDto> list) {
if ( list == null ) {
return null;
}
List<Child> list1 = new ArrayList<Child>( list.size() );
for ( ChildDto childDto : list ) {
list1.add( childDtoToChild( childDto ) );
}
return list1;
}
主要问题:如何强制 Mapstruct 使用 parent.addChild (...)
来保持 parent 和 Child 列表之间的 bi-directional 映射。
我的结构比较复杂,有多个嵌套children,所以要考虑可扩展性。
找了半天,找到了目前最好的解决方案。它没有使用特殊的方法,但它允许你保持双向连接。
@AfterMapping
default void mapBidirectional(@MappingTarget Parent parent){
List<Child> childList = parent.getChildList();
if (childList != null) {
childList.forEach(child -> child.setParent(parent));
}
}
将会
@Override
public Parent toEntity(ParentDto parentDto) {
if ( parentDto == null ) {
return null;
}
Parent parent = new Parent();
parent.setChildList( childDtoListToChildList( parentDto.getChildList() ) );
mapBidirectional( parent );
return parent;
}
但是这个问题很可能还有另一种解决方案,因为双向通信非常普遍,而且这种解决方案的扩展性不好
而且不能拆分成几个*Mapping类,因为不能在@AfterMapping方法中使用生成的变量
MapStruct有Collection Mapping Strategies的概念。它允许您在映射时使用加法器。
例如
@Mapper(componentModel = "spring", collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
public interface TestMapper {
Parent toEntity(ParentDto parentDto);
}
我有双向映射 (@OneToMany Hibernate) 和额外的方法来确保 object 链接。 简单示例:
@Setter
class ParentDto {
List<ChildDto> childList;
}
@Setter
class ChildDto {
String text;
}
@Setter
class Parent {
List<Child> childList;
public void addChild(Child child) {
childList.add(child);
child.setParent(this);
}
}
@Setter
class Child {
Parent parent;
String text;
}
映射器:
@Mapper(componentModel = "spring")
public interface TestMapper {
Parent toEntity(ParentDto parentDto);
}
生成:
public class TestMapperImpl implements TestMapper {
@Override
public Parent toEntity(ParentDto parentDto) {
if ( parentDto == null ) {
return null;
}
Parent parent = new Parent();
parent.setChildList( childDtoListToChildList( parentDto.getChildList() ) );
return parent;
}
protected Child childDtoToChild(ChildDto childDto) {
if ( childDto == null ) {
return null;
}
Child child = new Child();
child.setText( childDto.getText() );
return child;
}
protected List<Child> childDtoListToChildList(List<ChildDto> list) {
if ( list == null ) {
return null;
}
List<Child> list1 = new ArrayList<Child>( list.size() );
for ( ChildDto childDto : list ) {
list1.add( childDtoToChild( childDto ) );
}
return list1;
}
主要问题:如何强制 Mapstruct 使用 parent.addChild (...)
来保持 parent 和 Child 列表之间的 bi-directional 映射。
我的结构比较复杂,有多个嵌套children,所以要考虑可扩展性。
找了半天,找到了目前最好的解决方案。它没有使用特殊的方法,但它允许你保持双向连接。
@AfterMapping
default void mapBidirectional(@MappingTarget Parent parent){
List<Child> childList = parent.getChildList();
if (childList != null) {
childList.forEach(child -> child.setParent(parent));
}
}
将会
@Override
public Parent toEntity(ParentDto parentDto) {
if ( parentDto == null ) {
return null;
}
Parent parent = new Parent();
parent.setChildList( childDtoListToChildList( parentDto.getChildList() ) );
mapBidirectional( parent );
return parent;
}
但是这个问题很可能还有另一种解决方案,因为双向通信非常普遍,而且这种解决方案的扩展性不好
而且不能拆分成几个*Mapping类,因为不能在@AfterMapping方法中使用生成的变量
MapStruct有Collection Mapping Strategies的概念。它允许您在映射时使用加法器。
例如
@Mapper(componentModel = "spring", collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED)
public interface TestMapper {
Parent toEntity(ParentDto parentDto);
}