Micronaut Data 数据传输对象(DTO)投影,包含连接实体的属性。

6

我使用 Micronaut Data 和 JPA,有两个实体。第一个实体是 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
}

第二个是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
}

现在我希望在API中提供DTO,并且使用ParseError属性而不是整个Recipe实体,因为它包含了ManyToOne和OneToMany关系,在这种情况下是不必要的。所以我为此创建了投影DTO。
@Introspected
public class ParseErrorDto {
    private Integer recipeId;

    private String recipeName;

    private ParseError.ProblemArea problemArea;

    private String message;

// + getters and setters
}

并将listAll()方法添加到ParseErrorRepository中:

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

但是似乎Micronaut Data无法从嵌套实体中投影属性,或者我在DTO或存储库方法中错过了某些东西:

ParseErrorRepository.java:22:错误:无法实现仓库方法:ParseErrorRepository.listAll()。实体中不存在属性recipeId:ParseError

我还尝试创建RecipeDto

@Introspected
public class RecipeDto {
    private Integer id;

    private String name;

    // + getters and setters
}

并相应更新ParseErrorDto

@Introspected
public class ParseErrorDto {
    private RecipeDto recipe;

    private ParseError.ProblemArea problemArea;

    private String message;

    // + getters and setters
}

再次失败:

ParseErrorRepository.java:22: 错误:无法实现Repository方法:ParseErrorRepository.listAll()。类型为[RecipeDto]的属性[recipe]与实体中声明的等效属性不兼容:ParseError。

Micronaut Data能否通过DTO投影来处理此用例?如果不能,则是否有其他方式可以在Micronaut Data中解决此问题?


https://github.com/micronaut-projects/micronaut-data/issues/170 - Sascha Frinken
1
@SaschaFrinken 这是一个不同的问题,但我专门为这个案例创建了一个新的:https://github.com/micronaut-projects/micronaut-data/issues/184 - cgrim
1个回答

4
现在(在最新版本1.0.0.M1中)不可能。因此,我为此创建了功能请求问题:https://github.com/micronaut-projects/micronaut-data/issues/184 目前的解决方法是将实体bean映射到Java流或响应流中的DTO bean中,并手动执行属性映射或使用Mapstruct。
更新:以下是对评论中的问题的回答,以及使用Mapstruct执行解决方法的示例:
在build.gradle中添加Mapstruct依赖项:
implementation "org.mapstruct:mapstruct:$mapstructVersion"
annotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"
testAnnotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"

定义Mapper:

import org.mapstruct.Mapper;

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

    EntityReference recipeToDto(@NotNull Recipe recipe);
}

下面是控制器中使用该映射器的示例:

@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);
    }
}

1
嘿,我目前也遇到了同样的问题,你能否提供一个“手动”映射的示例吗?我的应用程序中有几个部分需要类似于转换器的东西,但我不知道做这件事的“最佳方式”是什么。 - Mafick
我添加了使用Mapstruct解决此问题的示例。 - cgrim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接