1

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'
}
2

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.