Reputation: 2268
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
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