如何修复 JPA 规范 API 的连接条件返回 2 个查询而不是 1 个?

发布于 2025-01-20 16:30:52 字数 1130 浏览 0 评论 0原文

我需要使用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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

巴黎盛开的樱花 2025-01-27 16:30:52

你在这里有单独的问题。要在单个查询中获取父实例及其子实例,您需要查看与您使用的“连接”语义不同的获取连接 - 请参阅 https://docs.oracle.com/javaee/6/api/javax/persistence/criteria/FetchParent.html。调用 root.fetch(PARENT_.ChildList, JoinType.LEFT) 将导致在同一个 SQL 语句中获取父级和子级,

但是当您查看 fetch joins 时,您会发现它们并没有支持查询过滤。当 JPA 返回托管实体时,因为它必须管理对这些实例的更改,所以它们必须准确反映数据库中的内容。如果您的父级仅包含部分填充的子级列表,则它在保存父级时无法真正知道要做什么;它应该修改该列表还是忽略它从数据库值中发现的差异。只是规范不支持它,并且查询语言也不允许它。您只是无法通过 JPA 语义按需获取父级和子级的部分列表。

不过你能做的就是自己去接孩子们。 This的等效项

"SELECT child, parent from Parent parent join parent.ChildList child where parent.id=:parentId and child.status in ('Active')"

将为您提供一个包含子项和父项对的 Object[} 列表,但仅包含活动的子实例。父实例将全部是 id 等于您作为查询参数传入的值的单个实例。如果你访问它的parent.ChildList,你会找到它的所有孩子 - 所以不要这样做。将其标记为惰性并且不要触摸它,并在操作中使用返回的子实例。

不过,您的查询只是要求表中的某些属性,所以我猜您并不真正需要完整的父/子实例。尝试使用 JPQL 数据查询:

@Query(value = "SELECT parent.id, parent.name, child.id, child.status from Parent parent join parent.ChildList child where parent.id=:parentId and child.status in ('Active')"

这将返回一个 List,其中 Object[] 包含每行的数据,无需使用 Spring 规范

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 statement

When 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

"SELECT child, parent from Parent parent join parent.ChildList child where parent.id=:parentId and child.status in ('Active')"

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:

@Query(value = "SELECT parent.id, parent.name, child.id, child.status from Parent parent join parent.ChildList child where parent.id=:parentId and child.status in ('Active')"

This will return a List<Object[]>, with the Object[] containing the data from each row, with no need to use Spring specifications

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文