首页 > 解决方案 > Spring Boot jpa 表层次结构

问题描述

我在数据库中只有一张名为Student的表。以下是我的代码中针对它的 jpa 实体:

@Entity
@Table(name = "student")
public class Student{

@Id
private Long id;

@Column
private String firstName;

@Column
@Embedded
@JsonUnwrapped
private School school;
}

public class School{

private Integer grade;//eg. 2nd, 3rd

private String type; //eg. primary, secondary
}

到目前为止,代码只是获取所有学生及其数据或获取特定学生。所以,数据库模式就是这样。但是现在,我们有一个新功能,我们需要根据特定成绩进行搜索并获取该特定成绩的所有学生。或获取特定学校类型的所有学生,例如。小学的所有学生。因此,需求完全相反,我们需要将以下模式的返回值发送到前端:

class SchoolResponseDTO{

private String schoolType;

private List<Integer> grades;
}

class Grade{

private Integer id;

private List<Integer> studentId;
}

稍微冗长一点,从现在开始,我们需要找到所有学校类型,然后是该学校类型中的所有年级,然后是该学校类型和年级中的所有学生。

到目前为止,我们一直在使用 Spring JpaRepository 来满足我们的需求。我觉得这个新要求需要自定义查询,我认为这不能使用 JPARepository 以直接的方式处理。我只需要知道你怎么想。这可以在没有自定义 sql 查询的情况下完成吗?

标签: javaspringspring-bootspring-data-jpaentity

解决方案


您可以使用 Spring Data 并使用类似于此查询属性表达式的内容。从文档:

属性表达式只能引用托管实体的直接属性,如前面的示例所示。在创建查询时,您已经确保解析的属性是托管域类的属性。但是,您也可以通过遍历嵌套属性来定义约束。考虑以下方法签名:

List<Person> findByAddressZipCode(ZipCode zipCode);

假设一个人有一个带有邮政编码的地址。在这种情况下,该方法会创建属性遍历 x.address.zipCode。解析算法首先将整个部分 (AddressZipCode) 解释为属性,并检查域类以查找具有该名称(未大写)的属性。如果算法成功,它将使用该属性。如果不是,算法将源代码从右侧拆分为头和尾,并尝试找到相应的属性——在我们的示例中为 AddressZip 和 Code。如果算法找到具有该头部的属性,它将获取尾部并继续从那里向下构建树,以刚才描述的方式将尾部拆分。如果第一个拆分不匹配,则算法将拆分点向左移动(地址、邮政编码)并继续。

虽然这应该适用于大多数情况,但算法可能会选择错误的属性。假设 Person 类也有一个 addressZip 属性。该算法将在第一轮拆分中匹配,选择错误的属性,然后失败(因为 addressZip 的类型可能没有 code 属性)。

要解决这种歧义,您可以在方法名称中使用 _ 来手动定义遍历点。所以我们的方法名称如下:

List<Person> findByAddress_ZipCode(ZipCode zipCode);

因为我们将下划线字符视为保留字符,我们强烈建议遵循标准 Java 命名约定(即,不在属性名称中使用下划线,而是使用驼峰式大小写)。

检查链接 https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-property-expressions

希望能帮助到你。


推荐阅读