我有以下数据(为了简洁和清晰,删除了其他字段):
@Entity
class CategoryEntity {
private Long id;
private String name;
}
@Entity
class ProductEntity {
private Long id;
private String name;
private CategoryEntity category;
}
输入的是
record ProductDto(String name, String categoryName) { }
Service 中的代码如下所示:
public ProductEntity processProduct(ProductDto productDto) {
// find and check it exists
CategoryEntity categoryEntity = categoryService.findCategoryByName(productDto.categoryName());
ProductEntity productEntity = productMapper.toEntity(productDto);
productEntity.setCategory(categoryEntity);
// do some processing
// ...
return productEntity;
}
如何实现映射器将 Product dto 转换为实体并使用提供的 Category 实体而无需手动设置?
我尝试将类别实体实例作为参数传递:
@Mapper
interface ProductMapper {
@Mapping(target = "category", source = "categoryEntity")
ProductEntity toEntity(ProductDto dto, CategoryEntity categoryEntity);
}
但在这种情况下,categoryEntity.id 用于设置结果productEntity.id 这是完全错误的。
这是带有 MapStruct 1.5.5 的 Quarkus 项目。
请记住,采用两个参数(没有
@MappingTarget
注释)的映射方法用于将合并对象到新对象中,因此,与源之一匹配的任何目标属性都用于映射。
在上面(简化的)情况下,您可以使用这种注释组合来达到您想要的目标:
@Mapping(target = "category", source = "categoryEntity")
@Mapping(target = "name", source = "dto.name")
@Mapping(target = "id", ignore = true)
ProductEntity toEntity(ProductDto dto, CategoryEntity categoryEntity);
第一个和你的一样;第二个是必要的,因为有两个
name
属性,您必须设置哪个属性必须用于目标。第三个是不使用 id
来设置 categoryEntity
。
生成的代码是这样的:
@Override
public ProductEntity toEntity(ProductDto dto, CategoryEntity categoryEntity) {
if ( dto == null && categoryEntity == null ) {
return null;
}
ProductEntity.ProductEntityBuilder productEntity = ProductEntity.builder();
if ( dto != null ) {
productEntity.name( dto.name() );
}
productEntity.category( categoryEntity );
return productEntity.build();
}
当然,这种方法可能无法扩展到您的情况,我的意思是:为了使其实现您想要的逻辑,您必须手动将源之间的每个冲突属性设置为手动映射,以及您不想要的每个属性被覆盖而被忽略。
也许在这种情况下,使用 mapstruct 并不是将
category
注入 product
实体的最佳解决方案,但我不知道您的应用程序的真正复杂性。