Blazebit / blaze-persistence

Rich Criteria API for JPA providers
https://persistence.blazebit.com
Apache License 2.0
713 stars 84 forks source link

Pagination in queries that join on an @OneToMany or @ManyToMany attribute return duplicate results #1914

Open rybandrei2014 opened 1 month ago

rybandrei2014 commented 1 month ago

Description

I need to retrieve paginated result with fetch and I am also getting duplicates in result. It happens when I am getting entities that have more than one attribute bound by @ManyToOne relation. Here is the pseudocode:

public class Entity {
    @Id
    private Long id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "entity")
    private Set<EntityAttribute> attributes;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, insertable = false, updatable = false)
    private EntityType entityType;
}

public class EntityAttribute {
    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, insertable = false, updatable = false)
    private Entity entity;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false, insertable = false, updatable = false)
    private Attribute attribute;
}

@Override
public PagedList<Entity> search(SearchByCodeRequest request) {
        var date = Optional.ofNullable(request.getDate()).orElse(new Date());
        var pageSize = request.getPageSize();
        var firstResult = request.getPage() * pageSize;

        var cb = criteriaBuilderFactory.create(entityManager, Entity.class)
                .fetch("entityType", "attributes", "attributes.attribute")
                .orderByAsc("id")
                .page(firstResult, pageSize)
                .withCountQuery(true)
                .where("validFrom").le(date)
                .where("validTo").ge(date);

        var code = request.getCode();

        if (code != null) {
            cb.where("entityType.code").eq(code);
        }

        var r = cb.getResultList();

        return r;
}

Here is pseudo result I am getting:

{
    "data": [
        {
            "id": 3,
            "entityType": {
                "code": "REGISTER"
            },
            "attributes": [
                {
                    "id": 4,
                    "attribute": {
                        "id": 4
                    }
                },
                {
                    "id": 7,
                    "attribute": {
                        "id": 8
                    }
                },
                {
                    "id": 5,
                    "attribute": {
                        "id": 6
                    }
                },
                {
                    "id": 6,
                    "attribute": {
                        "id": 7
                    }
                }
            ]
        },
        {
            "id": 3,
            "entityType": {
                "code": "REGISTER"
            },
            "attributes": [
                {
                    "id": 4,
                    "attribute": {
                        "id": 4
                    }
                },
                {
                    "id": 7,
                    "attribute": {
                        "id": 8
                    }
                },
                {
                    "id": 5,
                    "attribute": {
                        "id": 6
                    }
                },
                {
                    "id": 6,
                    "attribute": {
                        "id": 7
                    }
                }
            ]
        },
        {
            "id": 3,
            "entityType": {
                "code": "REGISTER"
            },
            "attributes": [
                {
                    "id": 4,
                    "attribute": {
                        "id": 4
                    }
                },
                {
                    "id": 7,
                    "attribute": {
                        "id": 8
                    }
                },
                {
                    "id": 5,
                    "attribute": {
                        "id": 6
                    }
                },
                {
                    "id": 6,
                    "attribute": {
                        "id": 7
                    }
                }
            ]
        },
        {
            "id": 3,
            "entityType": {
                "code": "REGISTER"
            },
            "attributes": [
                {
                    "id": 4,
                    "attribute": {
                        "id": 4
                    }
                },
                {
                    "id": 7,
                    "attribute": {
                        "id": 8
                    }
                },
                {
                    "id": 5,
                    "attribute": {
                        "id": 6
                    }
                },
                {
                    "id": 6,
                    "attribute": {
                        "id": 7
                    }
                }
            ]
        }
    ],
    "page": 1,
    "pageSize": 4,
    "total": 4
}

As you can see I get the same entity with Id = 3 4 times in the result set, due to 4 attributes bound to that entity. How can I remove such duplicates in result set? Thank you in advance

Expected behavior

No duplicates are returned in result

Actual behavior

Duplicates are returned when entity has several @OneToMany or @ManyToMany bonds fetched

Environment

Version: 1.6.11 JPA-Provider: Hibernate 6.4.4.Final DBMS: PostgreSQL 16

beikov commented 3 weeks ago

Please share the generated SQL queries.