【发布时间】:2019-06-04 14:53:30
【问题描述】:
如何使用 Spring JPA 的 Query by Example 不仅查询实体本身,还使用 findAll() 查询相关实体的属性?当在探针/示例实体上设置相关实体属性时,我们所有的尝试似乎都忽略了它们。
文档说明:
属性说明符接受属性名称(例如名字和姓氏)。您可以通过将属性与点 (address.city) 链接在一起进行导航。您还可以使用匹配选项和区分大小写来调整它。
但是,没有示例显示链接应该如何工作,我们尝试使用它也没有成功。
人为的例子
假设一个多对多关系的数据库结构:
-
表:书
- id(PK、INT)
- 标题(varchar)
- ...
-
表格:类别
- id(PK、INT)
- 姓名
- ...
-
表:Book_Category
- book_id
- category_id
Book.java
@Data
@Entity
public class Book {
public Book () {}
public Book(String title, List<Category> categories) {
this.title = title;
this.categories = categories;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@NotNull
private String title;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(
name = "book_category",
joinColumns = {@JoinColumn(name = "book_id")},
inverseJoinColumns = {@JoinColumn(name = "category_id")}
)
private List<Category> categories;
}
BookRepository.java
@Repository
public class BookRepository extends JpaRepository<Book, long> {
}
Category.java
@Data
@Entity
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@NotNull
private String name;
}
CategoryRepository.java
@Repository
public class CategoryRepository extends JpaRepository<Category, long> {
}
BookService.java
public class BookService {
@Autowired
private BookRepository bookRepository;
@Autowired
private CategoryRepository categoryRepository;
public List<Book> findByExample(String title, String category) {
ExampleMatcher matcher = ExampleMatcher.matchingAll()
.withMatcher("title", match -> match.contains().ignoreCase())
// ### This is (probably?) the bit that's wrong - none of these made any difference
//.withMatcher("categories.id", match -> match.contains())
//.withMatcher("categories.name", match -> match.contains().ignoreCase())
//.withMatcher("categories", match -> match.contains())
// ###
.withIgnoreNullValues() // ignore unset properties when finding
.withIgnorePaths("id"); // ignore primitives as they default to 0
List<Category> matchingCategories = categoryRepository.findAllByName(category);
Example<Book> example = Example.of(new Book(
title, matchingCategories), matcher);
return bookRepository.findAll(example)
}
}
调用 BookService.findByExample(...) 根据标题正确过滤,但完全忽略类别。 “真实”的例子更复杂,但这提炼了我们遇到的问题;我们如何过滤相关表以及基础表?
【问题讨论】: