I'm using @EntityGraph to eagerly load some attributes. However, something broke after updating from 5.x to 6.x. Suppose we have a human who can have multiple houses:
public class Human {
@Id
@Column(name = "ID", nullable = false, updatable = false, precision = 20)
@GeneratedValue
private BigInteger id;
@EqualsAndHashCode.Exclude
@ToString.Exclude
@OneToMany(mappedBy = "human", cascade = CascadeType.ALL)
@OnDelete(action = OnDeleteAction.CASCADE)
private Collection<House> houses;
}
When searching for a human, by ID, EntityGraph can eagerly load some attributes:
@EntityGraph(attributePaths = { "houses.address" })
@Query ("SELECT h FROM Human h WHERE h.id = ?1")
Human findByIdEagerHouseAddresses(Integer id);
This will create SQL with left (outer by default) joins:
select h1_0.id, h2_0.human_fk, h2_0.address_fk, a1_0.id
from human h1_0
left join house h2_0 on h1_0.id = h2_0.human_fk
left join address a1_0 on a1_0.id = h2_0.address_fk where h1_0.id in (?)
This is acceptable because I will get the human even if they don't have a house. However, if the address field in the house has the @Id annotation, the outer join will change to "inner":
@Entity
public class House {
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "human_fk", nullable = false, updatable = false)
private Human human;
@Id @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "address_fk", nullable = false, updatable = false)
private Address address;
}
select h1_0.id, h2_0.human_fk, h2_0.address_fk, a1_0.id
from human h1_0
left join house h2_0 on h1_0.id = h2_0.human_fk
join address a1_0 on a1_0.id = h2_0.address_fk where h1_0.id in (?)
If a human does not have a house, the query returns nothing due to the inner join, which seems like a bug. |