如何修复 JPA 规范 API 的连接条件返回 2 个查询而不是 1 个?
我需要使用JPA AS形成查询;
select PARENT.ID, PARENT.NAME, CHILD.ID, CHILD.STATUS FROM PARENT
LEFT OUTER JOIN CHILD ON PARENT.ID=CHILD.ID AND CHILD.STATUS in ('Active')
WHERE PARENT.ID=?
儿童桌与父母的关系。
使用JPA规格API,我在下面添加了谓词以加入
public static Specification<PARENT> hasChildrenWithStatus(List<String> status) {
return (root, criteriaQuery, criteriaBuilder)
-> {
Join<Object, Object> join = root.join(PARENT_.ChildList, JoinType.LEFT);
join.on(join.get(CHILDREN_.STATUS).in(status));
return criteriaBuilder.conjunction();
};
}
并为父母添加了其他谓词,但是我的查询
Hibernate: select PARENT.id as id1_0_, PARENT.name as namev2_0_
from PARENT PARENT
left outer join CHILD CHILD on (PARENT.id=CHILD.id) and (CHILD.status in('Active'))
where PARENT.id=? and 1=1
Hibernate: select CHILD.id as id5_2_0_, CHILD.status as stat4_2_1_ from CHILD CHILD where CHILD.id=?
在第二个查询中作为2个不同的查询执行,以获取所有记录,带有Child.ID(无状态检查),因此给了我记录。在“已删除”状态中。
我该如何解决?另外,可以按照我的要求将其作为单个查询执行?
I have a requirement to form a query using JPA as;
select PARENT.ID, PARENT.NAME, CHILD.ID, CHILD.STATUS FROM PARENT
LEFT OUTER JOIN CHILD ON PARENT.ID=CHILD.ID AND CHILD.STATUS in ('Active')
WHERE PARENT.ID=?
Where child table is OneToMany relation to its parent.
Using JPA Spec API I have added below Predicate for Join
public static Specification<PARENT> hasChildrenWithStatus(List<String> status) {
return (root, criteriaQuery, criteriaBuilder)
-> {
Join<Object, Object> join = root.join(PARENT_.ChildList, JoinType.LEFT);
join.on(join.get(CHILDREN_.STATUS).in(status));
return criteriaBuilder.conjunction();
};
}
and added other predicates for PARENTs, but my query executed as 2 different queries
Hibernate: select PARENT.id as id1_0_, PARENT.name as namev2_0_
from PARENT PARENT
left outer join CHILD CHILD on (PARENT.id=CHILD.id) and (CHILD.status in('Active'))
where PARENT.id=? and 1=1
Hibernate: select CHILD.id as id5_2_0_, CHILD.status as stat4_2_1_ from CHILD CHILD where CHILD.id=?
Here in the second query fetches all records with child.id(without status check), thus giving me records that are in "deleted" status as well.
How can I fix this? Also, Can this be executed as single query as my requirement?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你在这里有单独的问题。要在单个查询中获取父实例及其子实例,您需要查看与您使用的“连接”语义不同的获取连接 - 请参阅 https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/FetchParent.html。调用 root.fetch(PARENT_.ChildList, JoinType.LEFT) 将导致在同一个 SQL 语句中获取父级和子级,
但是当您查看 fetch joins 时,您会发现它们并没有支持查询过滤。当 JPA 返回托管实体时,因为它必须管理对这些实例的更改,所以它们必须准确反映数据库中的内容。如果您的父级仅包含部分填充的子级列表,则它在保存父级时无法真正知道要做什么;它应该修改该列表还是忽略它从数据库值中发现的差异。只是规范不支持它,并且查询语言也不允许它。您只是无法通过 JPA 语义按需获取父级和子级的部分列表。
不过你能做的就是自己去接孩子们。 This的等效项
将为您提供一个包含子项和父项对的 Object[} 列表,但仅包含活动的子实例。父实例将全部是 id 等于您作为查询参数传入的值的单个实例。如果你访问它的parent.ChildList,你会找到它的所有孩子 - 所以不要这样做。将其标记为惰性并且不要触摸它,并在操作中使用返回的子实例。
不过,您的查询只是要求表中的某些属性,所以我猜您并不真正需要完整的父/子实例。尝试使用 JPQL 数据查询:
这将返回一个 List
You've got separate issues here. To fetch parent instances with its children in a single query, you need to look at fetch joins which are different from the 'join' semantics you've used - see https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/FetchParent.html. Calling
root.fetch(PARENT_.ChildList, JoinType.LEFT)
will cause the Parent and children to be fetched in the same SQL statementWhen you look at fetch joins though, you'll see that they do not support query filtering. When JPA returns managed entities, because it must manage changes to those instances, they must reflect exactly what is in the database. If you get a parent with only a partially populated list of children, it can't really know what to do when it saves the parent; should it modify that list or just ignore differences it finds from the database values. It is just not supported by the spec, and the query language doesn't allow it. You just can't fetch Parents and partial lists of the children on demand though JPA semantics.
What you can do though is fetch the children yourself. The equivalent of
This will give you a list of Object[} containing child and parent pairs, but only active child instances. The Parent instance will all be the single instance with id equal to the value you pass in as a query parameter. If you access its parent.ChildList though, you will find all its children - so don't. Mark it as lazy and don't touch it, and use the returned child instances in your operations.
Your query though is just asking for certain attributes from the tables, so I'm guessing you don't really need full Parent/Child instances. Try a JPQL data query instead:
This will return a List<Object[]>, with the Object[] containing the data from each row, with no need to use Spring specifications