Hello! I’m using Spring Data JPA and I’m in need of some help. I got the following entities:
Order Entity:
public class Order {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(mappedBy = "order", cascade = CascadeType.ALL, optional = false, fetch FetchType.LAZY)
@JsonManagedReference
private Cart cart;
Cart Entity:
public class Cart {
@Id
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Order order;
@OneToMany(mappedBy = "cart",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<OrderItem> orderItems;
OrderItem Entity:
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Cart cart;
The following methods
@Query("from Order order " +
"join fetch order.cart as cart " +
"join fetch cart.orderItems " +
"where order.id = :orderId")
OrderDTO findDTOById(Long orderId);
And
OrderDTO order = entityManager.createQuery("""
select new OrderDTO(
order.id,
order.createdOn,
order.updatedOn,
order.formattedCreatedOn,
order.formattedUpdatedOn,
order.address,
order.orderDetails,
order.cart)
from Order order join fetch order.cart.orderItems where order.id = :orderId""",
OrderDTO.class)
.setParameter("orderId", orderId)
.getSingleResult();
Result in org.hibernate.NonUniqueResultException: Query did not return a unique result: 2 results were returned
The DB looks like this:
Order Table:
+----+
| id |
+----+
| 1 |
+----+
Cart Table:
+----------+
| order_id |
+----------+
| 1 |
+----------+
OrderItem table:
+----+---------+
| id | cart_id |
+----+---------+
| 1 | 1 |
| 2 | 1 |
+----+---------+
However, fetching only the Cart works fine:
@Override
public Cart findCartByOrderId(Long orderId) {
return entityManager.createQuery("select order.cart from Order order join fetch order.cart.orderItems where order.id = :orderId",
Cart.class).
setParameter("orderId", orderId)
.getSingleResult();
}
Fetching the entity itself Order without a DTO also works without an issue:
@Query("from Order order " +
"join fetch order.cart as cart " +
"join fetch cart.orderItems " +
"where order.id = :orderId")
Order findByIdNoLazy(Long orderId);
It seems the issue appears when using either a Interface-based Projection or a Class-based Projection as a DTO with these particular mappings.
At the moment I can only achieve fetching an OrderDTO (the objective is to omit fetching the user) by fetching the OrderDTO without selecting order.cart and after it has been fetched I do
order.setCart(findCartByOrderId(orderId)).
I don’t know what causing this or why HB is looking for one/unique result to begin with, instead of fetching the orderItems collection. Is there anything I can do to avoid fetching the cart separately when fetching an order dto?
Thank you very much!