Hibernate JOIN FETCH - Objects appear multiple times in Resultset

ε祈祈猫儿з 提交于 2019-12-10 11:38:33

问题


I am using Spring JPA and Hibernate to build a REST API. I am searching for 2 days, but i didn't find any solution to fix this issue.

In some queries i have multiple JOIN FETCH clauses. When I execute my query i have the parent object multiple times in my result set, in fact exactly as often as the father has children.
Example:

    @Query("SELECT DISTINCT p AS post," +
        " <some subquery>" +
        "FROM Post p  JOIN FETCH p.user u LEFT JOIN FETCH p.linkedUsers INNER JOIN FETCH p.track track  " 
        "WHERE ( (<some condition>) OR p.user = :me) " +
        "ORDER BY p.created DESC")
List<Object []> getData(@Param("me")User me,
                                 Pageable pageable);

For example if i have a post with 2 linked users my post will appear at least 2 times in my result set. If i don't do the JOIN FETCH or an other JOIN the data is loaded lazily. But this is not a goal for me since it causes a bad performance.

Edit: So my question is, how to execute one query where all data is fetched and all posts which met the specified criteria are only ONE time in my resultset.

Edit:

Example object is:

 [{
    "id": 1767,
    "track": {
        "id": 1766,
        "title": "VVS",
        ...
        "streams": [
            {
                "id": 1764,
                 ....
            },
            {
                "id": 1765,
                  ...

            }
        ],
        "isrc": "DEQ021801393"
    },
    "user": {
        "id": 999998,
        "username": "My username",
         ....

    },
    "created": "2018-08-21T22:18:56.451Z",
     ...
    "linked_users": []
},
<this object another time, beacause two stream objects in track>
<many other objects two times>
...
]

Edit:

It turned out, that the subqueries stand in conflict with the "distinct". If i remove them from the query i get distinct posts. If i edit the native sql query and alter the "distinct" to a "distinct on" it works. But i think a "distinct on" clause doesn't exist in hibernate. So any good ideas what to do?

I would appreciate any help :)


回答1:


In jpa 2.1, it support entity graph to solve the "Duplicate and N+1 issues"

@NamedEntityGraph(name = "graph.Order.items", 
               attributeNodes = @NamedAttributeNode(value = "items", subgraph = "items"), 
subgraphs = @NamedSubgraph(name = "items", attributeNodes = @NamedAttributeNode("product")))

Use entity graph to load data:

Map hints = new HashMap();
hints.put("javax.persistence.fetchgraph", graph);

return this.em.find(Order.class, orderId, hints);

More detail:

https://www.thoughts-on-java.org/jpa-21-entity-graph-part-1-named-entity/




回答2:


If anyone is interested in how i solved the problem:

After weeks of ignoring this problem i found a solution. I am pretty sure that it cannot be solved by using HQL, so i wrote a native query by using postgreSQLs json_build_object method. All data is produced on database level and fetched as a list of JSON Objects. This has the advantage that the performance of the query is much better.

Query Structure:

SELECT DISTINCT ON(post.created)json(json_build_object('id',...
'user', (SELECT json_build_object('id',... 
            FROM users WHERE users.id = post.user_id)
'track', (SELECT json_build_object('id',....
     'streams',ARRAY(SELECT json_build_object('id'...
FROM
<APPORXIMATELY Same JOINS AS BEFORE>
WHERE
<CONDITIONS>

Execute query from SpringBoot:

 List<JsonNode> decoratedPosts = (List<JsonNode>) entityManager
                .createNativeQuery(NativeQueries.getPostsByUser)
                .setParameter("userId", user.getId())
                .setParameter("me", requestor.getId())
                .setParameter("limit", pageable.getPageSize())
                .setParameter("offset", pageable.getOffset())
                .unwrap(org.hibernate.query.NativeQuery.class)
                .addScalar("json", JsonNodeBinaryType.INSTANCE).getResultList();

To get this work the following dependency is needed (depending on your hibernate version):

    <dependency>
        <groupId>com.vladmihalcea</groupId>
        <artifactId>hibernate-types-52</artifactId>
        <version>2.3.4</version>
    </dependency>

And the hibernate dialect needs to be extended.

public class MariosPostgreSQL94Dialect extends PostgreSQL94Dialect {

public MariosPostgreSQL94Dialect() {
    super();
    this.registerColumnType(Types.OTHER, "json");
}


来源:https://stackoverflow.com/questions/52494249/hibernate-join-fetch-objects-appear-multiple-times-in-resultset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!