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

And*_*708 14 java spring hibernate jpa spring-mvc

我有一个基于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);
Run Code Online (Sandbox Code Playgroud)

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

在这里,我只需获取一个Company带有填充reviews集合的对象.这在上面的场景中很有效.但是,如果我想获取给定公司的全部或部分评论呢?也就是说,Review与具有给定ID的公司相关联的对象.我想用一个List<Review>而不是一个Company对象List<Review>.这只是一个例子 - 基本上我正在寻找比仅仅基于主键查找对象更多的灵活性.我可以用HQL做到没有问题,但是我必须编写几个类似的查询,具体取决于我在特定上下文中需要哪些数据.

find方法javax.persistence.EntityManager简单地使得可以基于主键查询对象.但是在某种程度上可以在更复杂的场景中使用实体图,例如使用Criteria对象还是HQL查询?例如,查找具有其他条件而不是主键的对象 - 甚至可能是关联条件.

我希望我清楚自己.提前致谢!

And*_*i I 14

您正在寻找的可能不是EntityGraphs,而是JPA Query(JP NamedQuery或者是a 或a的形式CriteriaQuery).这是JPA规范的全部内容.

所以基本上你可以:

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

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


Ala*_*Hay 8

如你所知:

我可以用HQL做到没有问题,但是我必须编写几个类似的查询,具体取决于我在特定上下文中需要哪些数据.

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

public interface CompanyRepository{

    List<Review> findAll(Criteria criteria, FetchPlan fetchPlan);
}
Run Code Online (Sandbox Code Playgroud)

Spring Data项目实际上可以让我们成为现在的一部分,但目前并不是所有方式(尽管有关于缺失部分的讨论:请参见下文).

它目前做的是第一部分:

public interface CompanyRepository{

    List<Review> findAll(Criteria criteria);

}
Run Code Online (Sandbox Code Playgroud)

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

使用QueryDSL方法,我们可以创建一个这样的Repository定义:

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

}
Run Code Online (Sandbox Code Playgroud)

现在,在没有创建实现(由框架创建)或编写任何更多代码的情况下,我们可以使用以下任何属性组合来调用它:

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"));
Run Code Online (Sandbox Code Playgroud)

等等....

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

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

除了创建一些接口定义之外,这为您提供了很少的(零)代码,但是仍然需要额外的(在DB交互方面次优)机制来处理延迟加载,即在您的其他内容中突出显示的机制之一最近的问题,导致了这个问题.

然而,我没有看到为什么Spring Data无法更新以处理EntityGraphs的动态规范,并且确实已经围绕这个进行了一些讨论,所以它可能正在进行中:

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

所以可能值得提出一个JIRA来看看他们正在计划或要求的东西

/sf/users/1268571/

直.

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

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