如何使用Spring JPA的Query by Example不仅可以查询实体本身,还可以使用findAll()
查询相关实体的属性?当我们在探针/示例实体上设置相关实体属性时,我们所有的尝试似乎都只是忽略它们。
文档指出:
属性说明符接受属性名称(例如名字和姓氏)。您可以通过将属性与点(address.city)链接在一起进行导航。您还可以使用匹配选项和区分大小写对其进行调整。
但是,没有任何示例显示链接应该如何工作,并且我们尝试使用链接没有成功。
设计示例
假定数据库结构具有多对多关系:
表格:图书
表:类别
表格:Book_Category
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(...)会根据标题正确过滤,但完全忽略该类别。 “真实的”示例更为复杂,但这提炼了我们遇到的问题。我们该如何过滤相关表和基础表?
答案 0 :(得分:0)
这仅适用于ToOne关系,不适用于您的情况下的ToMany:
属性说明符接受属性名称(例如名字和 姓)。您可以通过将属性和点链接在一起来进行导航 (地址。城市)。您还可以使用匹配的选项和大小写对其进行调整 敏感性。
我还查看了Spring Data源代码,这里是:
for (SingularAttribute attribute : type.getSingularAttributes()) {
因此,它仅使用SingularAttribute之类的原语,String和ToOne关系。
所以我很害怕,但是您试图实现的目标似乎是不可能的。