2012-01-01 50 views
0

使用Hibernate我有以下查询JPQL加盟,where子句有意想不到的效果

String PQ = "select k from Customer k inner join k.winterSet vs where vs.year = :year"; 
    TypedQuery<Customer> tq = legacyEm.createQuery(PQ,Customer.class); 
    tq.setParameter("year", DateUtil.getCurrentWinterSeason()); 
    List<Customer> result = tq.getResultList(); 

在客户的映射

@OneToMany(fetch = FetchType.LAZY, mappedBy = "customer") 
private Set<Winter> winterSet = new HashSet<>(0); 

,并在冬季

@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "cnr") 
private Customer customer; 

当我运行这个查询我只从Customer中得到实际上在Winter中具有与该gi匹配的属性年的相关行的行ven参数。到现在为止还挺好。但是,这些Customer对象的WinterSet中填充了所有相关的Winter对象,而不仅仅是年份属性中具有所需值的那些对象。我怎样才能做到这一点?

回答

0

这是完全正常和预期的结果。通过映射,您可以定义实体的结构,包括与其他实体的关系。查询定义了哪些实体在结果中。

使用FetchType,您可以部分控制是否获取查询实体的一些持久性属性。但是没有机制来填充只有一些收集的元素。

如果您需要只呈现实体中某些部分数据的结果,那么您可以创建一个呈现部分结果的新类并使用查询和构造函数表达式填充它。

+0

事实证明,幸运的是有一种方法。否则,在我看来,jpa会非常适得其反。在查询中使用“连接获取”而不是“连接”会有诀窍。 – 2012-01-02 07:45:28

+0

它的工作原理,但只与休眠。 JPA通常不允许限制获取的实体。这确实非常危险,因为如果你修改了部分加载的集合,Hibernate会触发一个更新,并且可以很好地移除所有链接并重新创建它们,从而删除所有未加载实体的链接。 – 2012-01-02 08:05:40

+0

所以,实际上你说的是在EclipseLink或OpenJPA中运行fetch连接查询,检索到的对象集与Hibernate产生的不同?修改结果并不是必须的,但的确如此,也要感谢这个警告,在Hibernate中,获取连接看起来本质上是危险的......实际上没有安全和有效的方式来实现我想要的JPA吗?如果我只想要相关集合中的某个对象,我是否真的需要加载所有对象,只是将它们中的n-1扔掉? – 2012-01-02 09:31:06

0

加入提取的伎俩:

字符串PQ = “选择客户ķķ内连接抓取k.winterSet VS其中vs.year =:一年”;

调试hibernate表明生成的sql包含where子句。但是,由于关系映射为LAZY,因此不会从此查询填充集合,只会有Customer对象。稍后访问集合时,会触发加载,但此时,was-clause已经过去了,并且所有对象都已加载。

但是,当使用“join fetch”(实际上一次从查询中加载所有对象)时,hibernate填充查询结果集中的所有内容,因此只有所需的对象出现在集合中。这当然要高效得多,只有一个查询被执行了,之后不需要加载集合中的每个对象,只是为了抛弃大部分对象。

编辑:只在hibernate中有效,如果修改结果可能会有严重的副作用。见评论。