Hi
Given following model:
class Customer extends StandardEntity {
@Column(name = "NAME", nullable = false, length = 100)
protected String name;
@Composition
@OnDelete(DeletePolicy.CASCADE)
@OnDeleteInverse(DeletePolicy.UNLINK)
@OneToMany(mappedBy = "customer", orphanRemoval = true)
protected List<DeliveryAddress> deliveryAddresses = new ArrayList<>();
}
class DeliveryAddress extends StandardEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CUSTOMER_ID")
protected Customer customer;
@Column(name = "ADDRESS")
protected String address;
}
Use case : transfer delivery address from one customer to another using JPQL
Customer source;
Customer target;
@Before
public void setUp() {
testDb.clearData();
source = testDb.createCustomer("C1");
target = testDb.createCustomer("C2");
RefDataContext ctx = refData.newContext();
DeliveryAddress da = testDb.createDeliveryAddress("addr");
source.addDeliveryAddress(da, ctx);
ctx.commit();
}
@Test
public void transferDeliveryAddressCUBA() {
final String q = "UPDATE busy$DeliveryAddress e SET e.customer = :target WHERE e.customer = :source";
persistence.createTransaction().execute(em -> {
em.createQuery(q)
.setParameter("source", source)
.setParameter("target", target)
.executeUpdate();
});
}
@Test
public void transferDeliveryAddressJPA() {
final String q = "UPDATE busy$DeliveryAddress e SET e.customer = :target WHERE e.customer = :source";
persistence.createTransaction().execute(em -> {
em.getDelegate().createQuery(q)
.setParameter("source", source)
.setParameter("target", target)
.executeUpdate();
});
}
Using CUBA, I have the following exception, while using JPA this works.
java.lang.IllegalArgumentException: You have attempted to set a value of type class java.util.UUID for parameter source with expected type of class com.busy.app.entity.com.Customer from query string UPDATE busy$DeliveryAddress e SET e.customer = :target WHERE e.customer = :source.
at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:937)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:594)
at com.haulmont.cuba.core.sys.QueryImpl$Param.apply(QueryImpl.java:655)
at com.haulmont.cuba.core.sys.QueryImpl.getQuery(QueryImpl.java:145)
at com.haulmont.cuba.core.sys.QueryImpl.executeUpdate(QueryImpl.java:382)
Why using JPQL ? For performance, because there will be a lot of entities with customer references to change, this is just an example.
In the meantime I will use JPA queries, but is there any risk doing so ?
EDIT: anticipating the remark, using “SET e.customer.id = :target” instead of “SET e.customer = :target” is not allowed by JPA
Exception Description: Problem compiling [UPDATE busy$DeliveryAddress e SET e.customer.id = :target WHERE e.customer = :source].
[34, 47] An association field cannot be used in an update item's path expression.
Mike