4

I'm trying to delete an entity using HQL and it's failing.

    TypedQuery<Seller> query = Seller.entityManager().createQuery(
        "DELETE FROM Seller AS o WHERE o.company=:company AND o.id=:id", Seller.class);
    query.setParameter("company", company);
    query.setParameter("id", id);
    int result = query.executeUpdate();

The stacktrace I'm getting:

Update/delete queries cannot be typed; nested exception is java.lang.IllegalArgumentException: Update/delete queries cannot be typed
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:296)
    at org.springframework.orm.jpa.aspectj.JpaExceptionTranslatorAspect.ajc$afterThrowing$org_springframework_orm_jpa_aspectj_JpaExceptionTranslatorAspect$1$18a1ac9(JpaExceptionTranslatorAspect.aj:33)
    at com.ahp.core.model.Seller.deleteSeller_aroundBody4(Seller.java:111)
    at com.ahp.core.model.Seller.deleteSeller(Seller.java:1)
    at com.ahp.core.processor.SellerProcessor.delete(SellerProcessor.java:175)
    at com.ahp.core.processor.SellerProcessor.consume(SellerProcessor.java:80)
    at com.ahp.core.processor.SellerProcessor.consume(SellerProcessor.java:1)
    at com.ahp.messaging.processor.AbstractRPCConsumer.onMessage(AbstractRPCConsumer.java:32)
    at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:228)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:756)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:679)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:82)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:167)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1241)
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:660)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1005)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:989)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:82)
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1103)
    at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.IllegalArgumentException: Update/delete queries cannot be typed
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.resultClassChecking(AbstractEntityManagerImpl.java:363)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:344)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:366)
    at com.sun.proxy.$Proxy57.createQuery(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:241)
    at com.sun.proxy.$Proxy56.createQuery(Unknown Source)
    ... 18 more

Seller.java was generated by Spring Roo:

@RooJavaBean
@RooToString
@RooJpaActiveRecord
public class Seller {
...

Seller_Roo_Jpa_Entity.aj:

privileged aspect Seller_Roo_Jpa_Entity {

    declare @type: Seller: @Entity;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long Seller.id;

    ...

Seller_Roo_Jpa_ActiveRecord.aj:

privileged aspect Seller_Roo_Jpa_ActiveRecord {

    @PersistenceContext
    transient EntityManager Seller.entityManager;

    ...

I've tried changing the delete method to look like this so that I don't use TypedQuery at all:

import javax.transaction.Transactional;

...

@Transactional
public static Boolean deleteSeller(Company company,  Long id){
    Query query = Seller.entityManager().createQuery(
            "DELETE FROM Seller AS o WHERE o.company=:company AND o.id=:id");
    query.setParameter("company", company);
    query.setParameter("id", id);
    int result = query.executeUpdate();
    return result > 0;
}

... but this is giving me another exception:

org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:316)
    at org.springframework.orm.jpa.aspectj.JpaExceptionTranslatorAspect.ajc$afterThrowing$org_springframework_orm_jpa_aspectj_JpaExceptionTranslatorAspect$1$18a1ac9(JpaExceptionTranslatorAspect.aj:33)
    ...
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
    at org.hibernate.jpa.spi.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:71)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:311)
    at com.sun.proxy.$Proxy58.executeUpdate(Unknown Source)
    ... 18 more

My method is annotated with @Transactional, so I don't see how it is not inside a transaction.

This question and this question seems to be using HQL to do a delete query, so it must be possible, what am I missing here?

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
Jan Vladimir Mostert
  • 12,380
  • 15
  • 80
  • 137

1 Answers1

10

Change your DELETE query to:

Query query = Seller.entityManager().createQuery(
    "DELETE FROM Seller AS o WHERE o.company=:company AND o.id=:id");
query.setParameter("company", company);
query.setParameter("id", id);
int result = query.executeUpdate();

The DML JPQL queries are not typed, because they only return the affected rows and so they don't need a return type.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • The only interface in EntityManager that allows me to specify any sort of generics is when using TypedQuery, don't see Query anywhere, unless that Query is not of type javax.persistence.Query? – Jan Vladimir Mostert May 03 '15 at 22:00
  • You don't need generics for DELETE queries. You need to use the `Query createQuery(String qlString)` method instead. Generics are used when you want to return the generified parameter in your result, which is not the case for DML statements. – Vlad Mihalcea May 03 '15 at 22:03
  • I think what you meant to say is, `Query query = Seller.entityManager().createQuery( "DELETE FROM Seller AS o WHERE o.company=:company AND o.id=:id");`, that's how I got it if you read the second part of my question, but that's throwing a `TransactionRequiredException` – Jan Vladimir Mostert May 04 '15 at 04:57
  • True. I forgot to remove the generic part. You also need to add transactions – Vlad Mihalcea May 04 '15 at 05:18
  • I've changed Transactional from `javax.transaction.transactional` to `org.springframework.transaction.annotation.Transactional` and it's working now. IDE imported the wrong transactional annotation. – Jan Vladimir Mostert May 04 '15 at 05:26
  • I am facing the similar issue. I corrected from TypedQuery to Query, but my delete has a where "in" condition. If the all records are found then it successfully deletes, else even if one record from the "where in" clause is missing, I get an exception. Is it a must that all records must be present to delete successfully? – nikhilvora Oct 13 '16 at 12:38