具有 Spring 数据 Jdbc 的映射结构

Mapstruct with Spring Data Jdbc

我正在使用 Spring 数据 Jdbc 并且我有 2 个与参考 ID 相关的聚合。

public class ResourceEntity {

@Id
@With
private final UUID id;
private String institutionId;
private String version;  
private Long resourceTypeId;

public class ResourceTypeEntity {

@Id @With
private final Long id;
private String name;

我想将其映射为将被翻译的 GRPC 消息

public class Resource {
    private String institutionId;
    private String version;  
    private String name; <-- This should be mapped after lookup the ResourceTypeEntity byId
}

我创建了这样一个 ResourceMapper

@Mapper(unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE,
        collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface ResourceMapper {

    ResourceMapper mapper = Mappers.getMapper(ResourceMapper.class);

    @Mapping(target = "name", source = "resourceTypeId", ????
    Resource toResource(ResourceEntity resourceEntity);

    List<Resource> toResources(List<ResourceEntity> resourceEntities);

基本上我想使用 resourceTypeRepository.findById(resourceTypeId) 来获取 ResourceTypeEntity 并映射名称。

怎么做?

谢谢

只要您需要自动装配存储库以获取对象及其名称以进行进一步映射,您就没有机会通过接口实现这一点。但是,您可以使用 abstract class 代替,它与 MapStruct class 生成完全兼容,包括 Spring 组件模型。

@Mapper(
        componentModel = "spring",
        unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE,
        collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
        nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public abstract static class ResourceMapper {

    @Autowired
    private ResourceTypeRepository repository;

    public abstract Resource toResource(ResourceEntity resourceEntity);

    public abstract List<Resource> toResources(List<ResourceEntity> resourceEntities);

    @AfterMapping
    public void afterMapping(@MappingTarget Resource resource, ResourceEntity entity) {
        
        long id = resourceEntity.getResourceTypeId();

        // Call the repository to fetch ResourceTypeEntity by resourceTypeId
        // The method results in Optional<ResourceTypeEntity> so you might want to 
        // ... throw an exception or use a default value if no entity by id is found
        String name = repository.findById(id)
            .map(ResourceTypeEntity::getName)
            .orElse(null);                      

        resource.setName(name);
    }
}
@Autowire
private ResourceMapper resourceMapper;

void foo() {
    ResourceEntity resourceEntity = ...
    Resource resource = resourceMapper.toResource(resourceEntity);
}

记住这是一个 service 而不仅仅是 entity-dto mapper 只要里面的逻辑不是微不足道的并且取决于数据库连接和数据。我宁愿创建一个 @Service ,它使用 interface ResourceMapper 的方法不获取数据(取而代之的是服务层)但通过 @Context 传递 name:

Resource toResource(ResourceEntity entity, @Context String name);

@AfterMapping
void toResourceAfterMapping(
    @MappingTarget Resource resource, ResourceEntity entity, @Context String name
) {
    resource.setName(name);
}