当前位置: 首页 > 知识库问答 >
问题:

Spring 数据 JPA:按连接表中的属性排序后的重复记录

欧阳正德
2023-03-14

我在我的项目中遇到了一个麻烦,因此我将提供一个使用演示项目的例子。想象有两个实体:老师和学生。

@Entity
@Table(name = "STUDENTS")
public class Student {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String surname;

    @ManyToOne
    private Teacher teacher;

    // getters and setters
}
@Entity
@Table(name = "TEACHERS")
public class Teacher  {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String surname;

    @OneToMany(mappedBy = "teacher")
    List<Student> students = new ArrayList<>();

    // getters and setters

}

有一个存储库和一个服务类:

public interface TeacherRepository extends PagingAndSortingRepository<Teacher, Long>, JpaSpecificationExecutor<Teacher> {
}
@Service
public class TeacherService {

    @Autowired
    private TeacherRepository teacherRepository;

    @Autowired
    private TeacherToDTOMapper teacherToDTOMapper;

    public Page<TeacherDTO> findAll(Pageable pageable) {
        Specification<Teacher> specification = (root, criteriaQuery, criteriaBuilder) -> {

            return criteriaBuilder.lessThanOrEqualTo(root.get("id"), 2);
        };
        return teacherRepository.findAll(specification, pageable).map(teacherToDTOMapper::mapEntityToDTO);
    }
}

最后,一个控制器类:

@RestController
public class TeacherController {

    @Autowired
    private TeacherService teacherService;

    @GetMapping("/teachers")
    @ResponseStatus(HttpStatus.OK)
    public PagedModel<EntityModel<TeacherDTO>> findAll(PagedResourcesAssembler<TeacherDTO> resourcesAssembler, Pageable pageable) {
        Page<TeacherDTO> page = teacherService.findAll(pageable);
        return resourcesAssembler.toModel(page);
    }
}

在UI上有一个教师表。

用户筛选出具有 ID 的教师

然而,实际结果是:

{
  "_embedded": {
    "teacherDTOList": [
      {
        "id": 1,
        "name": "Aliyah",
        "surname": "Wiggins",
        "students": [
          {
            "id": 1,
            "name": "Amina",
            "surname": "Parks"
          },
          {
            "id": 2,
            "name": "Caleb",
            "surname": "Baker"
          },
          {
            "id": 3,
            "name": "Valentino",
            "surname": "Kent"
          },
          {
            "id": 4,
            "name": "Jaron",
            "surname": "Luna"
          },
          {
            "id": 5,
            "name": "Cayden",
            "surname": "Hoover"
          }
        ]
      },
      {
        "id": 1,
        "name": "Aliyah",
        "surname": "Wiggins",
        "students": [
          {
            "id": 1,
            "name": "Amina",
            "surname": "Parks"
          },
          {
            "id": 2,
            "name": "Caleb",
            "surname": "Baker"
          },
          {
            "id": 3,
            "name": "Valentino",
            "surname": "Kent"
          },
          {
            "id": 4,
            "name": "Jaron",
            "surname": "Luna"
          },
          {
            "id": 5,
            "name": "Cayden",
            "surname": "Hoover"
          }
        ]
      },
      {
        "id": 2,
        "name": "Macy",
        "surname": "Reyes",
        "students": [
          {
            "id": 6,
            "name": "Jasmin",
            "surname": "Friedman"
          },
          {
            "id": 7,
            "name": "Randall",
            "surname": "Archer"
          },
          {
            "id": 8,
            "name": "Caroline",
            "surname": "Davila"
          },
          {
            "id": 9,
            "name": "Sarah",
            "surname": "Pace"
          }
        ]
      }
    ]
  },
  "_links": {
    "self": {
      "href": "http://localhost:8080/teachers?page=0&size=3&sort=students.name,asc"
    }
  },
  "page": {
    "size": 3,
    "totalElements": 3,
    "totalPages": 1,
    "number": 0
  }
}

Aliyah Wiggins有重复的记录。我还没有找到适当的方法来获得预期的结果,所以现在我认为搜索与一个实体相关的对象并按另一个实体中的属性排序是不对的。演示项目可在此处获得。

共有3个答案

燕扬
2023-03-14

您可以将查询设置为返回规范中的不同值:

criteriaQuery.distinct(true);

这通常由Spring Data在findAll方法上设置为true,但在您使用自己的规范时并未暗示。您现在可以看到数据库连接查询的结果(教师将为每个学生重复一次)。

我建议向模型添加一个标志属性,而不是按 id 跳过。引入隐藏/删除/私有之类的内容将简化代码并使其更具可读性。然后,您可以使用一个空的存储库接口方法:findByActiveTrue();

蓬意致
2023-03-14

我认为以学生(即多人)的名字来排序教师(即一对多关系中的“一个”)是错误的。在尝试按学生的名字排序后,我们会得到以下结果:

ROW    TEACHER_NAME     TEACHER_SURNAME     STUDENT_FULL_NAME
1      Evan             Fuentes             Allyson Noble
2      Aliyah           Wiggins             Amina Parks
3      Evan             Fuentes             Ashlyn Berg
4      Aliyah           Wiggins             Caleb Baker
...

老师可以同时是第一个、第三个和最后一个。因此,这种排序方式毫无意义。此外,多对多在示例中更合适,但仍然没有改变事实。

濮阳
2023-03-14

您可以使用命名实体图来避免重复记录。

@NamedEntityGraph(name = "Teacher.students" ,attributeNodes = @NamedAttributeNode("students"))
@Entity
@Table(name = "TEACHERS")
public class Teacher  {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String surname;

    @OneToMany(mappedBy = "teacher")
    List<Student> students = new ArrayList<>();

    // getters and setters

}

并将findAll方法重写为

@EntityGraph(value = "Teacher.students" , type = EntityGraphType.LOAD)
Page<Teacher> findAll(Specification<Teacher> spec, Pageable pageable);
 类似资料:
  • 问题内容: 我正在尝试在Spring数据存储库中定义一个方法,以按日期排序获取表上的最后一条记录。这是我的实体: 这是我的存储库: 如果我尝试使用启动项目,则会收到下一个错误: 原因:org.springframework.data.mapping.PropertyReferenceException:未找到类型为Date的属性desc!遍历的路径:News.publicationDate。 如果

  • 我有一个使用Spring Boot 1.5.1和Spring Data Rest的数据库服务。我将我的实体存储在MySQL数据库中,并使用Spring的PagingAndSorting Repository通过REST访问它们。我发现这表明支持按嵌套参数排序,但我找不到按嵌套字段排序的方法。 我有以下课程: 例如,当使用该方法时: 并调用 URI http://localhost:8080/peo

  • 我正在尝试使用限制查询来限制查询结果。在没有限制的情况下,查询按预期工作。 但当我尝试使用limit(记录数)来限制记录时,如下所示:, 从上面的查询中,我得到了以下错误, 如何在spring data jpa查询中使用order by limit查询?

  • 得到一些问题与桌子布线。我需要为每个用户uniq购物车,在那里我将存储书籍。 当我在DB中打开AppUser表时,“cart_id”列始终为NULL。 购物车表只有id列-不确定是否应该这样 谢谢! 购物车

  • 问题内容: 我现在只需获取数组的前3个对象并映射它们: 每个都有一个属性(champ.level)。 如何将输出分类到 前三个切片中? 问题答案: 与自定义比较功能一起使用时,首先要进行降序排序: 使用ES6甚至更好:

  • 我有长ID的数组列表 我有一个具有