spring-data-jpa - 如何使用 Spring Data Rest 和 queryDSL 在连接表中查询多个值
问题描述
我正在为现有且相当旧的 mySQL 数据库编写新的 Spring Data REST 后端。我需要支持自由格式的搜索查询,而 queryDSL 似乎是一个不错的选择。一切正常,除了我无法在连接表中查询多个值。
这是我的实体和学生存储库(在 queryDSL 中,我想将所有字符串匹配查询默认为 LIKE):
@Data
@Entity
@Table(name = "students")
public class Students {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Integer id;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name", nullable = false)
private String lastName;
@Column(name = "major", nullable = false)
private String major;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "students_courses_joins", joinColumns = {
@JoinColumn(name = "student_id") }, inverseJoinColumns = {
@JoinColumn(name = "course_id") })
private List<Course> courses;
}
@Data
@Entity
@Table(name = "courses")
public class Courses {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", unique = true, nullable = false)
private Integer id;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "code", nullable = false)
private String code;
@ManyToMany(mappedBy = "courses")
List<Student> students;
}
RepositoryRestResource(collectionResourceRel = "students", path = "students")
public interface StudentsRepository extends JpaRepository<Students, Integer>,
QuerydslPredicateExecutor<Students>, QuerydslBinderCustomizer<QStudents> {
@Override
default void customize(@NonNull QuerydslBindings bindings, @NonNull QStudents Students) {
bindings.bind(String.class).first((StringPath path, String value) -> path.containsIgnoreCase(value));
}
DDL 创建连接表:
create table students_courses_joins
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`student_id` int(11) NOT NULL,
`course_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `student` (`student_id`),
KEY `course` (`course_id`),
CONSTRAINT `student` FOREIGN KEY (`student_id`) REFERENCES `students` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `course` FOREIGN KEY (`course_id`) REFERENCES `courses`(`id`) ON
DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
像这样的查询
http://localhost:8081/students?courses.name=XYZ&major=ABC
工作正常,但是一旦我尝试查询参加多门课程的学生,例如
http://localhost:8081/students?courses.name=XYZ&courses.name=MN
只接受连接表中的第一个参数,其余的被忽略。所以我只能查询学生是否参加了一门特定的课程,而不能查询多门课程。是 queryDSL 的限制还是我的设置有问题?
根据https://www.logicbig.com/tutorials/spring-framework/spring-data/web-query-dsl-collection-properties.html它应该可以正常工作,但是引用连接表的第二个查询参数总是被忽略. 我还尝试实现自定义 REST 控制器,而不是依赖 Spring 提供的控制器,但结果是一样的/
解决方案
您必须像这样修改customize
实现StudentRepository
(使用all
that takeMultiValueBinding
而不是first
that takes SingleValueBinding
):
@Override
default void customize(@NonNull QuerydslBindings bindings, @NonNull QStudent Students) {
bindings.bind(String.class).all((StringPath path, Collection<? extends String> value) -> {
BooleanBuilder builder = new BooleanBuilder();
Iterator<? extends String> iterator = value.iterator();
while (iterator.hasNext()) {
builder.or(path.containsIgnoreCase(iterator.next()));
}
return Optional.of(builder);
});
}
这样,您将收到如下查询:
SELECT student0_.id AS id1_1_,
student0_.first_name AS first_na2_1_,
student0_.last_name AS last_nam3_1_,
student0_.major AS major4_1_
FROM students student0_
WHERE EXISTS (SELECT 1
FROM students_courses_joins courses1_,
courses course2_
WHERE student0_.id = courses1_.student_id
AND courses1_.course_id = course2_.id
AND ( Lower(course2_.name) LIKE ? escape '!' ))
OR EXISTS (SELECT 1
FROM students_courses_joins courses3_,
courses course4_
WHERE student0_.id = courses3_.student_id
AND courses3_.course_id = course4_.id
AND ( Lower(course4_.name) LIKE ? escape '!' ))
LIMIT ?
推荐阅读
- python - Python:如何解析这个列表?
- javascript - 如何在完成选择项目之前停止关闭 Kendo MultiColumnDropDown?
- java - 简单的 ArrayList.remove(int) 不起作用。我做错了什么?
- python - MongoEngine python库过滤器查询获取本机mongo语法
- laravel - 决赛桌的雄辩模型关系
- pandas - pandas:px.parallel_coordinates,如何调整每个轴的间隔?
- c++ - 警告 LNK4099:找不到 PDB 'vc110.pdb'
- python - 按名称重新定义 python 函数的默认参数
- python - 解析 csv 转换的 json 文件获取句子为 NaN
- java - bluemix 中的资源管理和 JDBC 中准备好的语句的显式闭包