简体   繁体   中英

Hibernate left join fetch on many returns duplicities

I have a problem, I am using Hibernate via Spring data and I have this data model (model is much bigger but this is the part that causes problems).

Lets assume we have Entity A and Entity B . Relationship between two entities are Many-to-Many .

I am trying to fetch A records with B recordes fetched (to prevent lazy loading).

The model is connected like this

On entity A:

@ManyToMany(mappedBy = "items")
private List<BEntity> bs = new ArrayList<>();

On entity B

@ManyToMany
@JoinTable(
        name = "a_b",
        joinColumns = { @JoinColumn(name = "b_id", referencedColumnName = "id") },
        inverseJoinColumns = { @JoinColumn(name = "a_id", referencedColumnName = "id") }
)
private Collection<AEntity> as = new ArrayList<>();

So its typical M:N relationship. And I am trying to retrieve A data like following

@Query("SELECT a FROM AEntity a " +
        "   LEFT JOIN FETCH a.bs" +
        "WHERE a.id IN (:aIds)")
List<AEntity> findX(@NonNull @Param("aIds") Collection<Long> aIds);

The resulted SQL is something like

select X -- select fields omitted for simplicity
from item itembo0_
         left outer join a_b ab on a.id = ab.a_id
         left outer join b b on ab.b_id = b.id
where a.id in (...)

Which is a thing I would expect. The SQL will result duplicites (which I would expect as well cause there might be many B records which each has one result row). But at the end, hibernate does not merge all these rows into a A entity with fetched B fields .

For example, when I pass a 5 IDS into "in" condition, I get a 10 A records. Each one has a 2 B records linked! Thats the weird part .

Is there anyone who can tell me why hibernate does not merge these SQL results by A.id identifier and makes duplicites? Is it because I am asking for a List instead of Set?

Using the "DISTINCT" keyword in your query should be enough to avoid duplicates:

@Query("SELECT DISTINCT a FROM AEntity a " +
        "   LEFT JOIN FETCH a.bs" +
        "WHERE a.id IN (:aIds)")
List<AEntity> findX(@NonNull @Param("aIds") Collection<Long> aIds);

I do not know what kind of data you store, but perhaps a better solution, as you have mentioned, would be to use a Set instead of a List.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM