CUBA Update Query : wrong type exception when using an Entity parameter

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

Hi Mike,

It’s because of implicit conversion of a parameter of Entity type to its id mentioned here. So you just have to invoke setParameter("source", source, false) to avoid the issue.

See also my comments here.

Ok understood. Thanks Konstantin.

Is it possible at some point to be able to do the same (enable or disable implicit conversions) with LoadContext query? Or a global parameter because we do not want them at all.

In our code sometimes we use JPQL (for which we disable implicit conversions) sometimes DataManager, it would help us to be consistent : same JPQL query construct in both case.

It is done for 6.9, see https://youtrack.cuba-platform.com/issue/PL-10403. So you will have setParameter(String name, Object value, boolean implicitConversions) in LoadContext.

great, thanks Konstantin