Bojan Vukasovic
Bojan Vukasovic

Reputation: 2268

Hibernate: cannot force version increment on non-versioned entity

I have following simple code that basically creates entity with collections nested 2 levels deep. Then I save the collection, and I fetch collection again from DB, update it and try saving again. Hibernate gives me following exception:

Unable to perform beforeTransactionCompletion callback: cannot force version increment on non-versioned entity;

The problem is in this code (when I remove it it works) @Query("SELECT re FROM RootEntity re LEFT JOIN FETCH re.collects WHERE re.id=:id") but I do not know why it doesn't allow me to eagerly fetch the collection?

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@RequiredArgsConstructor
@Component
class Clr implements CommandLineRunner{

    private final RootEntityRepository repository;
    private Clr self;

    @Autowired
    @Lazy
    public void setClr(Clr clr) {
        this.self = clr;
    }

    @Transactional(Transactional.TxType.REQUIRES_NEW)
    public void save(RootEntity r){
        repository.save(r);
    }

    @Transactional(Transactional.TxType.REQUIRES_NEW)
    public void updateAndSave(String id) {
        Optional<RootEntity> oe = repository.findById(id);

        RootEntity e = oe.get();

        e.getCollects().stream().findFirst().get().getEmbeddedCollects().stream().findFirst().get().setValue("v2");

        repository.save(e);
    }

    @Override
    public void run(String... args) throws Exception {
        EmbeddedCollect ec = new EmbeddedCollect();
        ec.setValue("v1");

        Collect cl = new Collect();
        cl.getEmbeddedCollects().add(ec);

        RootEntity re = new RootEntity();
        cl.setRoot(re);
        re.setId("1");
        re.getCollects().add(cl);

        self.save(re);

        self.updateAndSave(re.getId());
    }
}

@Repository
interface RootEntityRepository extends JpaRepository<RootEntity, String>{
    @Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
    @Query("SELECT re FROM RootEntity re LEFT JOIN FETCH re.collects WHERE re.id=:id")
    Optional<RootEntity> findById(String id);
}

@Entity @Getter @Setter
class RootEntity{
    @Id
    private String id;
    @OneToMany(
            mappedBy = "root",
            cascade = CascadeType.ALL,
            orphanRemoval = true)
    private Set<Collect> collects = new HashSet<>();
    @Version private Long version;
}
@Entity @Getter @Setter
class Collect{
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ElementCollection
    private Set<EmbeddedCollect> embeddedCollects = new HashSet<>();
    @ManyToOne private RootEntity root;
}
@Embeddable @Getter @Setter
class EmbeddedCollect{
    @Column(name = "val")
    private String value;
}

and the code for spring boot application.properties file:

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.sql.init.platform=h2

with these gradle deps:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Upvotes: 1

Views: 1552

Answers (1)

Jared Renzullo
Jared Renzullo

Reputation: 144

Why are you adding the force optimistic lock mode to your query? @Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT). This forces the@Version field in an entity to be incremented. I think the issue is that your query is joining an Entity "Collect" which does not have a @Version field. So I would try either adding an @Version field to the "Collect" entity or removing that @Lock from the query.

Upvotes: 1

Related Questions