chr*_*ris 47 java jpa criteria jpa-2.0
考虑以下JPQL查询:
SELECT foo FROM Foo foo
INNER JOIN FETCH foo.bar bar
WHERE bar.baz = :baz
Run Code Online (Sandbox Code Playgroud)
我正在尝试将其转换为Critieria查询.这是我得到的:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Foo> cq = cb.createQuery(Foo.class);
Root<Foo> r = cq.from(Foo.class);
Fetch<Foo, Bar> fetch = r.fetch(Foo_.bar, JoinType.INNER);
Join<Foo, Bar> join = r.join(Foo_.bar, JoinType.INNER);
cq.where(cb.equal(join.get(Bar_.baz), value);
Run Code Online (Sandbox Code Playgroud)
这里显而易见的问题是我正在进行两次相同的连接,因为Fetch<Foo, Bar>
似乎没有方法来获取Path
.有没有办法避免必须加入两次?或者我是否必须坚持使用简单的查询这么好的旧JPQL?
Jam*_*mes 67
在JPQL中,规范中的情况也是如此.JPA规范不允许将别名赋予获取连接.问题在于,通过限制连接提取的上下文,您可以轻松地用脚拍摄自己.加入两次会更安全.
这通常是ToMany比ToOnes更多的问题.例如,
Select e from Employee e
join fetch e.phones p
where p.areaCode = '613'
Run Code Online (Sandbox Code Playgroud)
这将错误地返回包含"613"区号中的数字的所有员工,但会遗漏返回列表中其他区域的电话号码.这意味着拥有613和416区号的电话的员工将丢失416电话号码,因此该对象将被破坏.
当然,如果你知道自己在做什么,那么额外的连接是不可取的,一些JPA提供者可能允许对连接提取进行别名,并且可能允许将Criteria Fetch转换为连接.
Dhe*_*rik 10
我将使用James回答的一个很好的例子并添加替代解决方案来直观地展示问题.
当您执行以下查询时,没有FETCH
:
Select e from Employee e
join e.phones p
where p.areaCode = '613'
Run Code Online (Sandbox Code Playgroud)
您将按照Employee
预期获得以下结果:
EmployeeId | EmployeeName | PhoneId | PhoneAreaCode
1 | James | 5 | 613
1 | James | 6 | 416
Run Code Online (Sandbox Code Playgroud)
但是当你添加FETCH
单词时JOIN
,会发生以下情况:
EmployeeId | EmployeeName | PhoneId | PhoneAreaCode
1 | James | 5 | 613
Run Code Online (Sandbox Code Playgroud)
生成的SQL是这两个查询相同,但在Hibernate中删除内存中416
,当你使用寄存器WHERE
的FETCH
加入.
因此,要带上所有手机并WHERE
正确应用,你需要有两个JOIN
:一个用于WHERE
另一个用于FETCH
.喜欢:
Select e from Employee e
join e.phones p
join fetch e.phones //no alias, to not commit the mistake
where p.areaCode = '613'
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
96291 次 |
最近记录: |