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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27360966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 11:40:44  来源:igfitidea点击:

Using JPA entity graph with complex conditions

javaspringhibernatespring-mvcjpa

提问by ba0708

I have a project built on Spring MVC + JPA + Hibernate. I am using entity graphs (JPA 2.1) for defining which data to fetch from the database, like in the example below.

我有一个基于 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);

My Reviewentity has an association with a Companyentity (ManyToOne).

我的Review实体与Company实体 ( ManyToOne)有关联。

Here I simply fetch a Companyobject with a populated reviewscollection. This works well in scenarios like the above. But what if I want to fetch all or some of the reviews of a given company? That is, the Reviewobjects that are associated with a company with a given ID. I want a List<Review>instead of a Companyobject with a List<Review>. This is just an example - basically I am looking for more flexibility than simply looking up an object based on a primary key. I can do it with HQL with no problem, but then I would have to write several similar queries depending on which data I need in a specific context.

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

The findmethod on javax.persistence.EntityManagersimply makes it possible to query for an object based on a primary key. But is it somehow possible to use entity graphs in more complicated scenarios, e.g. with Criteria objects or HQL queries? For example, looking up objects with other conditions than by primary key - perhaps even conditions on associations.

find上方法javax.persistence.EntityManager简单地使得能够查询基于一个主键的对象。但是是否可以在更复杂的场景中使用实体图,例如使用 Criteria 对象或 HQL 查询?例如,查找具有除主键以外的其他条件的对象 - 甚至可能是关联条件。

I hope I made myself clear. Thanks in advance!

我希望我说清楚了。提前致谢!

采纳答案by Andrei I

What you are looking for is probably not EntityGraphs, but JPA Query(either JPQL in form of a NamedQueryor a CriteriaQuery). This is all part of the JPA specification.

您正在寻找的可能不是EntityGraphs,而是 JPA Query(以 aNamedQuery或 a形式出现的 JPQL CriteriaQuery)。这是 JPA 规范的全部内容。

So basically you can:

所以基本上你可以:

  1. Annotate each entity clas with @NamedQueriesto specify JPQL queries. Their advantage is that their syntax is checked on deployment (deployment will fail if e.g. the NamedQueries access missing properties) and are reusable and disadvantage is: they are statically defined (but of course accept parameters).
  2. Construct on runtime JPQL querieswith EntityManager. I use NamedQueries more often than runtime queries because of the above mentioned advantages.
  3. Use the Criteria API, which has the advantage, they are type-safe, as you join/search/add conditions/play their with real Java Objects.
  1. 注释每个实体类@NamedQueries以指定 JPQL 查询。它们的优点是在部署时检查它们的语法(如果例如 NamedQueries 访问缺少的属性,则部署将失败)并且可重用,缺点是:它们是静态定义的(但当然接受参数)。
  2. 使用 EntityManager构建运行时 JPQL 查询。由于上述优点,我比运行时查询更频繁地使用 NamedQueries。
  3. 使用 Criteria API,它的优点是类型安全,当您加入/搜索/添加条件/使用真正的 Java 对象播放它们时。

Now about EntityGraphs: they are just a help so fetch additional fields from a query (no matter if you use EntityManager.find()with the additional properties map parameter or Query.setHints()). You could also use Subgraphs for more complex situations. Check thisand this example.

现在关于EntityGraphs:它们只是一个帮助,因此从查询中获取附加字段(无论您是否使用EntityManager.find()附加属性映射参数或Query.setHints())。您还可以将子图用于更复杂的情况。检查这个这个例子

回答by Alan Hay

As you note:

正如你所指出的:

I can do it with HQL with no problem, but then I would have to write several similar queries depending on which data I need in a specific context.

我可以用 HQL 毫无问题地做到这一点,但随后我将不得不编写几个类似的查询,具体取决于我在特定上下文中需要哪些数据。

I assume then that the ultimate solution would look something like the below where one query method can be defined but to which we can pass both dynamic criteria (be these either direct or nested properties of an Entity) and a dynamic fetch plan defining those EntityGraphs to be activated:

我假设最终的解决方案看起来像下面这样,其中可以定义一个查询方法,但我们可以将动态条件(实体的这些直接或嵌套属性)和定义这些 EntityGraphs 的动态获取计划传递给它被激活:

public interface CompanyRepository{

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

The Spring Data project can actually get us part of the way there but not, at the current time, all of the way (although there is some discussion around regarding the missing part: see further below).

Spring Data 项目实际上可以让我们完成部分任务,但目前还不能完全完成(尽管有一些关于缺失部分的讨论:请参见下文)。

What it does do at the moment is the first part:

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

public interface CompanyRepository{

    List<Review> findAll(Criteria criteria);

}

either by means of the Specification pattern (http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/#specifications) or, more simply, by using QueryDSL's fluent API as an alternative to the JPA Criteria API.

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

Using the QueryDSL approach then we can create a Repository definition like this:

使用 QueryDSL 方法然后我们可以像这样创建一个 Repository 定义:

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

}

Now, and without creating an implementation (created by the framework) or writing any more codewe can call it as below, with any combination of attributes:

现在,无需创建实现(由框架创建)或编写更多代码,我们可以使用任意属性组合调用它,如下所示:

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"));

etc....

等等....

where QReview is a Query Type auto generated by the QueryDSL library and giving you strongly typed queries and the findOne(Predicate predicate) and findAll(Precicate predicate) methods are inherited from:

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

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

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

This then gives you a lot for very little (zero) code other than creating some interface definitions but would still require an additional (sub-optimal in terms of DB interactions) mechanism for handling the lazy loading i.e. one of the mechanisms highlighted in your other recent question and which led on to this one.

除了创建一些接口定义之外,这将为您提供很多非常少的(零)代码,但仍然需要一个额外的(就 DB 交互而言不是最佳的)机制来处理延迟加载,即在您的另一个中突出显示的机制之一最近的问题,这导致了这个问题。

I do not see however why Spring Data could not be updated to handle the dynamic specification of EntityGraphs and there has indeed been some discussion around this so it may be in the pipeline:

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

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

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

so might be worth raising a JIRA to see if this something they are planning or asking

所以可能值得提出一个 JIRA 来看看他们是否正在计划或询问这件事

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

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

directly.

直接地。

Some support has been added to Spring Data for the new JPA 2.1 EntityGraph functionalityb however I do not see that it can be made to work with a generic query method like we want here:

Spring Data 已为新的 JPA 2.1 EntityGraph 功能b 添加了一些支持,但是我不认为它可以与我们在这里想要的通用查询方法一起使用:

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

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