I'm migrating from hibernate 5.6.15 to hibernate 6.2.3 and I have noticed some issues with the L2 cache when an entity has a composite Id with one of its field mapped from a many to one association. Entities
@Getter
@IdClass(ProductPK.class)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString(onlyExplicitlyIncluded = true)
@NoArgsConstructor(access = PROTECTED)
@Entity
@OptimisticLocking(type = OptimisticLockType.ALL)
@DynamicUpdate
@Cacheable
@Cache(usage = READ_WRITE)
@Table(name = "PRODUCTS")
public class Product {
public Product(String productId, Operator operator) {
this.productId = productId;
this.operator = operator;
}
@EqualsAndHashCode.Include
@ToString.Include
@Id
@Column(name = "PRODUCT_ID", nullable = false)
private String productId;
@Id
@EqualsAndHashCode.Include
@ToString.Include
@Getter
@Setter
@ManyToOne(fetch = LAZY)
@JoinColumn
private Operator operator;
@Column(name = "DESCRIPTION")
@Setter
private String description;
@AllArgsConstructor
@EqualsAndHashCode
@Getter
@Setter
@NoArgsConstructor(access = PRIVATE)
public static class ProductPK implements Serializable {
private String productId;
private String operator;
}
}
@Getter
@Entity
@ToString(onlyExplicitlyIncluded = true)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@NoArgsConstructor(access = PROTECTED)
@Table(name = "OPERATORS")
@OptimisticLocking(type = OptimisticLockType.DIRTY)
@DynamicUpdate
@Cacheable
@Cache(usage = READ_WRITE)
public class Operator {
public Operator(String operatorId) {
this.operatorId = operatorId;
}
@EqualsAndHashCode.Include
@ToString.Include
@Id
@Column(name = "OPERATOR_ID", nullable = false)
private String operatorId;
@OneToMany(mappedBy = "operator", cascade = {CascadeType.ALL}, orphanRemoval = true)
private List<Product> products = new ArrayList<>();
public void setProducts(List<Product> products) {
this.products = products;
}
}
First Test
@Test
void addProductAndReadFromCacheTest() {
String string = "ID";
String operatorID = "operatorID";
ProductPK id = new ProductPK(string, operatorID);
String test = "test";
Operator operator = new Operator(operatorID);
operatorDao.save(operator);
Product product = new Product(string, operator);
product.setDescription(test);
productService.addProduct(product);
Optional<Product> byId = productService.getProduct(id);
assertThat(byId.orElseThrow().getOperator().getOperatorId()).isEqualTo(operatorID);
Optional<Product> byId2 = productService.getProduct(id);
assertThat(byId2.orElseThrow().getOperator().getOperatorId()).isEqualTo(operatorID);
}
This test throw the following exception during Optional<Product> byId2 = productService.getProduct(id); execution:
Second Test
@Test
void addProductAndReadFromCacheReadOnlyTest() {
String string = "ID";
String operatorID = "operatorID";
ProductPK id = new ProductPK(string, operatorID);
String test = "test";
Operator operator = new Operator(operatorID);
operatorDao.save(operator);
Product product = new Product(string, operator);
product.setDescription(test);
productService.addProduct(product);
Optional<Product> byId = productService.getProduct(id);
assertThat(byId.orElseThrow().getOperator().getOperatorId()).isEqualTo(operatorID);
Optional<Product> byId2 = productService.readProduct(id);
assertThat(byId2.orElseThrow().getOperator().getOperatorId()).isEqualTo(operatorID);
}
This test raise the following exception. It seems that hibernate ignore that operator is a lazy fetched field.
|