【问题标题】:Spring JPA - findAll() with example/probe including related/joined entitySpring JPA - findAll() 与示例/探针包括相关/加入实体
【发布时间】: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(...) 根据标题正确过滤,但完全忽略类别。 “真实”的例子更复杂,但这提炼了我们遇到的问题;我们如何过滤相关表以及基础表?

【问题讨论】:

    标签: java spring hibernate jpa


    【解决方案1】:

    这仅适用于 ToOne 关系,不适用于您的情况下的 ToMany:

    属性说明符接受属性名称(例如名字和 姓)。您可以通过将属性与点链接在一起进行导航 (地址.城市)。您还可以使用匹配的选项和大小写对其进行调整 灵敏度。

    我还查看了 Spring Data 源代码,这里是:

    for (SingularAttribute attribute : type.getSingularAttributes()) {
    

    所以它只使用 SingularAttribute,如原语、String 和 ToOne 关系。

    所以我很害怕,但你试图实现的目标似乎是不可能的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-14
      • 1970-01-01
      • 2020-09-14
      • 1970-01-01
      相关资源
      最近更新 更多