Как можно использовать запрос Spring JPA на примере для запроса не только самой сущности, но и свойств связанной сущности с использованием findAll()
? Кажется, что все наши попытки просто игнорируют свойства связанных сущностей, когда они установлены в сущности probe / example.
В документации указано:
Спецификатор свойства принимает имена свойств (например, имя и фамилия). Вы можете перемещаться по цепочке свойств вместе с точками (address.city). Вы также можете настроить его с помощью соответствующих параметров и чувствительности к регистру.
Однако нет примера, показывающего, как должна работать цепочка, и наши попытки ее использовать не принесли успеха.
Придуманный пример
Предполагая структуру базы данных с отношением «многие ко многим»
Таблица: Книга
- id (PK, INT)
- title (varchar)
- ...
Таблица: Категория
Таблица: 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 (...) корректно фильтрует по заголовку, но полностью игнорирует категорию. «Реальный» пример более сложный, но это устраняет проблему, с которой мы сталкиваемся; как мы можем отфильтровать как связанную таблицу, так и базовую?