简体   繁体   English

Mapstruct 与 Spring Data Jdbc

[英]Mapstruct with Spring Data Jdbc

I'm using Spring Data Jdbc and I have 2 aggregates that are related with a reference id.我正在使用 Spring Data 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;

I want to map it a GRPC message which will be translated我想将其映射为将被翻译的 GRPC 消息

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

I have created a ResourceMapper like this我已经创建了一个这样的 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);

Essentially I want to use the resourceTypeRepository.findById(resourceTypeId) to get the ResourceTypeEntity and map the name.基本上我想使用 resourceTypeRepository.findById(resourceTypeId) 来获取 ResourceTypeEntity 并映射名称。

How to do that?怎么做?

Thanks谢谢

You have no chance to achieve that through an interface as long as you need to autowire the repository for sake of fetching the object and its name for further mapping.只要您需要自动装配存储库以获取对象及其名称以进行进一步映射,您就没有机会通过接口实现这一点。 You can, however, use an abstract class instead which is fully compatible with MapStruct class generating including the Spring component model.但是,您可以改用abstract class与 MapStruct 类生成完全兼容,包括 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);
}

Remember this is rather a service than just a entity-dto mapper as long as the logics inside is not trivial and is dependant on the database connection and data.请记住,只要内部的逻辑不是微不足道的并且依赖于数据库连接和数据,这更像是一种服务,而不仅仅是一个 entity-dto映射器 I'd rather create a @Service which uses interface ResourceMapper with a method that doesn't fetch the data (does the service layer instead) but passes name through @Context :我宁愿创建一个@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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM