简体   繁体   English

具有来自连接实体的属性的 Micronaut 数据 DTO 投影

[英]Micronaut Data DTO projection with properties from joined entities

I use Micronaut Data with JPA and have two entities.我将 Micronaut Data 与 JPA 一起使用,并有两个实体。 The first one is Recipe :第一个是Recipe

@Entity
public class Recipe {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    @ManyToOne
    private Category category;

    @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    private Set<Step> steps;

// + other fields, getters and setters
}

The second one is ParseError which refers to Recipe :第二个是ParseError ,它指的是Recipe

@Entity
@Table(name = "parse_error")
public class ParseError implements Serializable {
    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    private Recipe recipe;

    @Id
    @Enumerated(EnumType.ORDINAL)
    @Column(name = "problem_area")
    private ProblemArea problemArea;

    private String message;

// + other fields, getters and setters
}

Now I would like to provide DTO in API with ParseError properties but not with whole Recipe entity because it contains ManyToOne and OneToMany relations which are not needed in this case.现在我想在 API 中提供带有ParseError属性的 DTO,但不提供整个Recipe实体,因为它包含在这种情况下不需要的 ManyToOne 和 OneToMany 关系。 So I created projection DTO for that:所以我为此创建了投影DTO:

@Introspected
public class ParseErrorDto {
    private Integer recipeId;

    private String recipeName;

    private ParseError.ProblemArea problemArea;

    private String message;

// + getters and setters
}

And added listAll() method into ParseErrorRepository :并将listAll()方法添加到ParseErrorRepository

@Repository
public interface ParseErrorRepository extends CrudRepository<ParseError, Integer> {
    List<ParseErrorDto> listAll();
}

But it seems that Micronaut Data is not able to project properties from nested entities or I missed something in the DTO or the repository method:但似乎 Micronaut Data 无法从嵌套实体中投影属性,或者我错过了 DTO 或存储库方法中的某些内容:

ParseErrorRepository.java:22: error: Unable to implement Repository method: ParseErrorRepository.listAll(). ParseErrorRepository.java:22:错误:无法实现存储库方法:ParseErrorRepository.listAll()。 Property recipeId is not present in entity: ParseError实体中不存在属性 recipeId:ParseError

I also tried to create RecipeDto :我还尝试创建RecipeDto

@Introspected
public class RecipeDto {
    private Integer id;

    private String name;

    // + getters and setters
}

And updated ParseErrorDto accordingly:并相应地更新ParseErrorDto

@Introspected
public class ParseErrorDto {
    private RecipeDto recipe;

    private ParseError.ProblemArea problemArea;

    private String message;

    // + getters and setters
}

Again no success:再次没有成功:

ParseErrorRepository.java:22: error: Unable to implement Repository method: ParseErrorRepository.listAll(). ParseErrorRepository.java:22:错误:无法实现存储库方法:ParseErrorRepository.listAll()。 Property [recipe] of type [RecipeDto] is not compatible with equivalent property declared in entity: ParseError [RecipeDto] 类型的属性 [recipe] 与实体中声明的等效属性不兼容:ParseError

Is Micronaut Data able to handle this use case by DTO projection? Micronaut Data 是否能够通过 DTO 投影处理此用例? If not then is there another way how can I solve it in Micronaut Data?如果没有,那么还有另一种方法如何在 Micronaut Data 中解决它?

Now (in latest version 1.0.0.M1) it is not possible.现在(在最新版本 1.0.0.M1 中)这是不可能的。 So I created feature request issue for that:https://github.com/micronaut-projects/micronaut-data/issues/184所以我为此创建了功能请求问题:https://github.com/micronaut-projects/micronaut-data/issues/184

Current workaround is to map entity bean into DTO bean in Java stream or reactive stream for example and do the properties mapping manually or by Mapstruct. Current workaround is to map entity bean into DTO bean in Java stream or reactive stream for example and do the properties mapping manually or by Mapstruct.


Update: Here is an answer to question from comments with an example how to do the workaround using Mapstruct:更新:这是对评论中问题的回答,并附有如何使用 Mapstruct 解决方法的示例:

Add Mapstruct dependency into build.gradle :将 Mapstruct 依赖项添加到build.gradle 中

implementation "org.mapstruct:mapstruct:$mapstructVersion"
annotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"
testAnnotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"

Define mapper:定义映射器:

import org.mapstruct.Mapper;

@Mapper(
    componentModel = "jsr330"
)
public interface ParseErrorMapper {
    ParseErrorDto entityToDto(@NotNull ParseError parseError);

    EntityReference recipeToDto(@NotNull Recipe recipe);
}

And here is a usage of that mapper in the controller:这是 controller 中该映射器的用法:

@Controller("/parse-error")
public class ParseErrorController {
    private final ParseErrorRepository repository;
    private final ParseErrorMapper mapper;

    public ParseErrorController(ParseErrorRepository repository, ParseErrorMapper mapper) {
        this.repository = repository;
        this.mapper = mapper;
    }

    @Get("all")
    @Transactional
    public Page<ParseErrorDto> getAll(final Pageable pageable) {
        return repository.findAll(pageable).map(mapper::entityToDto);
    }
}

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

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