pirho
pirho

Reputation: 12215

JPA criteria Updatequery not really updating anything

I am not able to have update to really happen with Updatequery. Having a simple test class:

@Entity
@ToString(callSuper = true)
// query just for logging purposes
@NamedQuery(name="TestEntity.findAll", query="SELECT t FROM TestEntity t")
public class TestEntity {
    @Id
    @GeneratedValue
    private Long id;    
    private String message = "not altered";
}    

and a test like:

@Slf4j
@DataJpaTest
@org.springframework.transaction.annotation.Transactional(propagation =
                                Propagation.NOT_SUPPORTED)
@RunWith(SpringRunner.class)
public class TestEntityUpdateTest {

    @PersistenceContext
    private EntityManager em;

    private void buildTestEntity(int i) {
        em.persist(new TestEntity());
    }

    private void log(Object o) {
        log.info("\n{}", o);
    }

    @Test
    @Transactional
    public void testUpdate() {
        IntStream.range(1, 4).forEach(this::buildTestEntity);
        TypedQuery<TestEntity> tq =
                em.createNamedQuery("TestEntity.findAll", TestEntity.class);

        // log inserted stuff
        log.info("\nINSERTED rows");
        tq.getResultList().forEach(this::log);

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaUpdate<TestEntity> update =
                    cb.createCriteriaUpdate(TestEntity.class);
        Root<TestEntity> from = update.from(TestEntity.class);
        update.set(from.get("message"), "ALTERED TEXT!");
        int i = em.createQuery(update).executeUpdate();

        log.info("\nUPDATED {} rows", i);
        // log updated stuff
        tq.getResultList().forEach(this::log);
    }

}

It must be something very simple but I can not see what? I also tried em.flush() in every imaginable place.

Should there be some extra commit() or some Spring data setting somewhere?

Rows are inserted correctly. I can see corresponding log rows, like:

TestEntity(super=org.example.spring.entity.updatequery.TestEntity@230a73f2, id=1, message=not altered)

I can see update queries and bindings correct(?):

Hibernate:
update
test_entity
set
message=?
.... org.hibernate.type.descriptor.sql.BasicBinder:65 - binding parameter [1] as [VARCHAR] - [ALTERED TEXT!]

BUT after update I do not see the change, but:

TestEntity(super=org.example.spring.entity.updatequery.TestEntity@230a73f2, id=1, message=not altered)

Relevant parts from pom.xml (ask for more):

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.2.RELEASE</version>
</parent>
...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>test</scope>
    </dependency>
...

Upvotes: 0

Views: 1479

Answers (1)

JB Nizet
JB Nizet

Reputation: 691755

All your test happens in a single transaction, so the first time you load the entities, they're stored in the session cache. And the second time you load them, they're just retrieved from the session cache again: update queries bypass the cache.

You need to clear the EntityManager before fetching the entities again.

Upvotes: 4

Related Questions