使用具有复杂条件的 JPA 实体图

2022-09-03 13:20:50

我有一个建立在Spring MVC + JPA + Hibernate上的项目。我使用实体图(JPA 2.1)来定义要从数据库获取哪些数据,如下面的示例所示。

EntityGraph<Company> entityGraph = entityManager.createEntityGraph(Company.class);
entityGraph.addAttributeNodes("reviews");

Map<String, Object> hints = new HashMap<String, Object>();
hints.put("javax.persistence.loadgraph", entityGraph);

Company company = entityManager.find(Company.class, companyId, hints);

我的实体与实体 () 有关联。ReviewCompanyManyToOne

在这里,我只是获取一个带有填充集合的对象。这在上述情况下效果很好。但是,如果我想获取给定公司的全部或部分评论,该怎么办?即,与具有给定 ID 的公司关联的对象。我想要一个而不是一个带有.这只是一个例子 - 基本上我正在寻找更大的灵活性,而不是简单地基于主键查找对象。我可以毫无问题地使用HQL做到这一点,但是我必须根据我在特定上下文中需要哪些数据来编写几个类似的查询。CompanyreviewsReviewList<Review>CompanyList<Review>

的方法只是可以基于主键查询对象。但是,是否可以以某种方式在更复杂的场景中使用实体图,例如,使用 Criteria 对象或 HQL 查询?例如,查找具有除主键以外的其他条件的对象 - 甚至可能是关联条件。findjavax.persistence.EntityManager

我希望我把自己说清楚。提前致谢!


答案 1

您要查找的可能不是 s,而是 JPA 查询(以 a 或 a 的形式表示的 JPQL)。这都是 JPA 规范的一部分。EntityGraphNamedQueryCriteriaQuery

所以基本上你可以:

  1. 为每个实体 cla 添加注释以指定 JPQL 查询。它们的优点是它们的语法在部署时被检查(如果例如NamedQueries访问缺少的属性,部署将失败),并且是可重用的,缺点是:它们是静态定义的(但当然接受参数)。@NamedQueries
  2. 使用 EntityManager 在运行时 JPQL 查询上构造。由于上述优点,我比运行时查询更频繁地使用Namequeries。
  3. 使用标准API,它具有优势,它们是类型安全的,因为您可以加入/搜索/添加条件/使用真正的Java对象播放它们。

现在关于s:它们只是一个帮助,所以从查询中获取其他字段(无论你是与附加属性map参数还是Query.setHints()一起使用)。您还可以将子图用于更复杂的情况。检查此示例此示例EntityGraphEntityManager.find()


答案 2

如您所见:

我可以毫无问题地使用HQL做到这一点,但是我必须根据我在特定上下文中需要哪些数据来编写几个类似的查询。

然后,我假设最终的解决方案将如下所示,其中可以定义一个查询方法,但我们可以向其传递动态条件(这些实体的直接属性或嵌套属性)和定义要激活的实体图的动态提取计划:

public interface CompanyRepository{

    List<Review> findAll(Criteria criteria, FetchPlan fetchPlan);
}

Spring Data项目实际上可以让我们部分到达那里,但目前还不是一路走来(尽管关于缺失的部分有一些讨论:见下文)。

它目前所做的是第一部分:

public interface CompanyRepository{

    List<Review> findAll(Criteria criteria);

}

通过规范模式(http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/#specifications)或更简单地说,通过使用QueryDSL的流畅API作为JPA标准API的替代方案。

使用QueryDSL方法,我们可以创建一个存储库定义,如下所示:

public interface ReviewRepository extends CrudRepository<Review, Long>, QueryDslPredicateExecutor<Review>{

}

现在,无需创建实现(由框架创建)或编写更多代码,我们可以将其称为,如下所示,具有任何属性组合:

Review review = respository.findOne();
Iterable<Review> reviews = respository.findAll(QReview.review.created.eq(someDate));
Iterable<Review> reviews = respository.findAll(QReview.review.created.eq(someDate).and(QReview.review.creator.forename.eq("Jim"));
Iterable<Review> reviews = respository.findAll(QReview.review.created.eq(someDate).and(QReview.review.creator.forename.eq("Jim").and(QReview.review.company.name.eq("Amazon"));

等。。。。

其中 QReview 是由 QueryDSL 库自动生成的查询类型,并为您提供强类型查询,而 findOne(谓词谓词)和 findAll(谓词谓词)方法继承自:

http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/querydsl/QueryDslPredicateExecutor.html

然后,除了创建一些接口定义之外,这为您提供了很少(零)代码的大量内容,但仍然需要一个额外的(就数据库交互而言是次优的)机制来处理延迟加载,即您最近的另一个问题中突出显示的机制之一,并导致了这个问题。

然而,我不明白为什么Spring Data无法更新以处理EntityGraphs的动态规范,并且确实对此进行了一些讨论,因此它可能正在筹备中:

http://forum.spring.io/forum/spring-projects/data/108202-custom-fetch-groups-with-spring-data-jpa-possible

所以可能值得提出一个JIRA,看看他们是否在计划或要求什么

https://stackoverflow.com/users/18122/oliver-gierke

径直。

对新的JPA 2.1 EntityGraph功能b的Spring Data添加了一些支持,但是我没有看到它可以像我们想要的那样使用通用查询方法:

http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/#jpa.entity-graph


推荐