Mapstruct与Spring Data Jdbc

huangapple go评论72阅读模式
英文:

Mapstruct with Spring Data Jdbc

问题

我正在使用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;

我想将它映射为一个GRPC消息该消息将被翻译为

public class Resource {
    private String institutionId;
    private String version;
    private String name; <-- 在查找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并映射名称

如何做到这一点

谢谢
英文:

I'm using Spring Data Jdbc and I have 2 aggregates that are related with a reference 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

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

@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.

How to do that?

Thanks

答案1

得分: 0

以下是翻译好的内容:

你只要通过接口来实现是没有机会实现这一点的,因为你需要自动装配存储库以获取对象及其名称以便进行进一步的映射。但是,你可以使用一个抽象类,它完全与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();

        // 调用存储库以通过resourceTypeId获取ResourceTypeEntity
        // 该方法返回Optional<ResourceTypeEntity>,因此如果未找到id对应的实体,可能需要抛出异常或使用默认值
        String name = repository.findById(id)
            .map(ResourceTypeEntity::getName)
            .orElse(null);                      

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

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

请记住,这实际上是一个服务,而不仅仅是一个实体-DTO 映射器,因为内部的逻辑不是微不足道的,并且依赖于数据库连接和数据。我宁愿创建一个使用interface ResourceMapper@Service,其中有一个方法不会获取数据(而是由服务层处理),而是通过@Context传递name

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

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

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.

@Mapper(
		componentModel = &quot;spring&quot;,
		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&lt;Resource&gt; toResources(List&lt;ResourceEntity&gt; 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&lt;ResourceTypeEntity&gt; 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. 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:

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

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

</details>



huangapple
  • 本文由 发表于 2020年10月15日 01:45:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/64358810.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定