英文:
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 = "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. 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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论