So i have a big error when trying to do an update method in my spring application ,the problem is regarding to the Caracter class as thats the one the seems to generate it. When i set my stuff in main and try to update an Anime object in the database the Caracter class gives me the errors presented below
the code
package com.site.anime.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.*; import java.util.List; @Entity @NoArgsConstructor @AllArgsConstructor @Data public class Caracter { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String image; private String description; private Double overall_mark; @ManyToMany(cascade = { CascadeType.ALL }) private List<Anime> shows; }
package com.site.anime.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.annotations.Fetch; import javax.persistence.*; import java.util.HashMap; import java.util.List; import java.util.Map; @Entity @NoArgsConstructor @AllArgsConstructor @Data public class Anime { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String name; private String image; private Integer no_episodes; private String description; private Double overall_score; @ManyToMany(cascade = { CascadeType.ALL }) private List<Caracter> caracters; @OneToMany(cascade = { CascadeType.ALL }) private List<Review> reviews; @ManyToMany(cascade = { CascadeType.ALL }) private List<Category> categories; }
package com.site.anime.service.impl; import com.site.anime.model.Anime; import com.site.anime.repository.RepositoryShow; import com.site.anime.service.AnimeService; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import org.springframework.stereotype.Service; import javax.transaction.Transactional; import java.lang.reflect.Field; @Service public class AnimeServiceImpl implements AnimeService { private final RepositoryShow repositoryShow; public AnimeServiceImpl(RepositoryShow repositoryShow) { this.repositoryShow = repositoryShow; } @Override public Anime findFirstByName(String name) { return repositoryShow.findFirstByName(name); } @Override @Transactional public Anime updateAnime(Anime newShow) { Anime anime=repositoryShow.findById(newShow.getId()).orElseThrow(); //System.out.println(anime.getCaracters().get(0).getName()); if(newShow.getName()!=null){ anime.setName(newShow.getName()); } if(newShow.getImage()!=null){ anime.setImage(newShow.getImage()); } if(newShow.getNo_episodes()!=null){ anime.setNo_episodes(newShow.getNo_episodes()); } if(newShow.getDescription()!=null){ anime.setDescription(newShow.getDescription()); } if(newShow.getCaracters()!=null){ anime.setCaracters(newShow.getCaracters()); } if(newShow.getCategories()!=null){ anime.setCategories(newShow.getCategories()); } return anime; //anime=newShow; // Field[] fields = anime.getClass().getDeclaredFields(); // Field[] fields1 = newShow.getClass().getDeclaredFields(); // for(int i=0;i<fields.length;i++){ // if(fields[i]!=fields1[i]){ // fields[i]=fields1[i]; // } // } //return null; } }
package com.site.anime; import com.site.anime.model.*; import com.site.anime.repository.*; import com.site.anime.service.impl.AnimeServiceImpl; import com.site.anime.service.impl.CaracterServiceImpl; import com.site.anime.service.impl.UserServiceImpl; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @EnableJpaRepositories @SpringBootApplication public class AnimeApplication { public static void main(String[] args) { SpringApplication.run(AnimeApplication.class, args); } @Bean CommandLineRunner init(RepositoryShow repositoryShow, RepositoryCategory repositoryCategory, RepositoryCaracter repositoryCaracter, RepositoryUser repositoryUser, RepositorySuperUser repositorySuperUser, ProfileRepository profileRepository, AnimeServiceImpl animeService, CaracterServiceImpl caracterService, UserServiceImpl userService){ return args -> { List<Anime> shows=new LinkedList<>(); Caracter caracter=new Caracter(null,"Subaru","","",0.0,null); List<Caracter> caracters=new LinkedList<>(); caracters.add(caracter); Profile profile=new Profile(null,"","",18,"",null,null,null,null,null); Utilizator user=new Utilizator(null); user.setName("rusu"); //Review review=new Review(null,user,"",0); Review review=new Review(null,"",2,null,null,null); Review review1=new Review(null,"",5,null,null,null); List<Review> reviews=new LinkedList<>(); review.setUser(user); review1.setUser(user); reviews.add(review); reviews.add(review1); //profile.setUser(user); Anime show=new Anime(null,"ReZero Season 1","",25,"",0.0,null,reviews,null); shows.add(show); caracter.setShows(shows); show.setCaracters(caracters); review.setReviewed_show(show); review1.setReviewed_show(show); profile.setReviews(reviews); user.setProfile(profile); repositoryShow.save(show); repositoryCaracter.save(caracter); repositoryUser.save(user); System.out.println(animeService.findFirstByName("ReZero Season 1").getName()); //System.out.println(repositoryUser.findFirstByName("rusu").getName()); Anime show1=new Anime(null,"ReZero Season 2","",25,"",0.0,null,reviews,null); System.out.println(caracterService.findFirstByName("Subaru").getName()); System.out.println(userService.findFirstByName("rusu").getName()); //System.out.println(animeService.findFirstByName("ReZero Season 1")); Utilizator user1=new Utilizator(null); List<Review> reviews1=new LinkedList<>(); Review review2=new Review(null,"",2,null,null,null); Profile profile1=new Profile(null,"","",18,"",null,null,null,null,null); review2.setUser(user1); review2.setReviewed_show(show); reviews1.add(review2); profile1.setReviews(reviews1); user1.setProfile(profile1); repositoryUser.save(user1); show.setName("ReZero Season 2"); animeService.updateAnime(show); userService.deleteUser(user1); }; } }
and the error
java.lang.IllegalStateException: Failed to execute CommandLineRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:807) ~[spring-boot-2.4.3.jar:2.4.3] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:788) ~[spring-boot-2.4.3.jar:2.4.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:333) ~[spring-boot-2.4.3.jar:2.4.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) ~[spring-boot-2.4.3.jar:2.4.3] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) ~[spring-boot-2.4.3.jar:2.4.3] at com.site.anime.AnimeApplication.main(AnimeApplication.java:23) ~[classes/:na] Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: com.site.anime.model.Caracter; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.site.anime.model.Caracter at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:297) ~[spring-orm-5.3.4.jar:5.3.4] at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233) ~[spring-orm-5.3.4.jar:5.3.4] at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:566) ~[spring-orm-5.3.4.jar:5.3.4] at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:743) ~[spring-tx-5.3.4.jar:5.3.4] at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:711) ~[spring-tx-5.3.4.jar:5.3.4] at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:654) ~[spring-tx-5.3.4.jar:5.3.4] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:407) ~[spring-tx-5.3.4.jar:5.3.4] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.4.jar:5.3.4] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.4.jar:5.3.4] at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.4.jar:5.3.4] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.3.4.jar:5.3.4] at com.site.anime.service.impl.AnimeServiceImpl$$EnhancerBySpringCGLIB$$3ebceda5.updateAnime(<generated>) ~[classes/:na] at com.site.anime.AnimeApplication.lambda$init$0(AnimeApplication.java:91) ~[classes/:na] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:804) ~[spring-boot-2.4.3.jar:2.4.3] ... 5 common frames omitted Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.site.anime.model.Caracter at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:120) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:104) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.internal.SessionImpl.persistOnFlush(SessionImpl.java:765) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.spi.CascadingActions$8.cascade(CascadingActions.java:341) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:492) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:416) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:218) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:525) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:456) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:419) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:218) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:151) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:159) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:149) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:82) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:93) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1362) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:453) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3212) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2380) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101) ~[hibernate-core-5.4.28.Final.jar:5.4.28.Final] at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:562) ~[spring-orm-5.3.4.jar:5.3.4] ... 16 common frames omitted
Advertisement
Answer
I think that the issue here is, that you are replacing the characters collection with a new collection and the collection has different object than the persistence context, although it uses the same primary key. Since you are cascading changes, Hibernate tries to flush the changes and realizes that an entity for that primary key is already associated with the persistence context and fails to flush with the exception you are seeing. If you want to just apply the entity to the database, try to use entityManager.merge
without loading the entity first. Alternatively, you could also try to apply the collections like this:
if (newShow.getCaracters()!=null) { for (Character c : newShow.getCaracters()) { anime.getCaracters().add(entityManager.getReference(Character.class, c.getId()); } } if (newShow.getCategories()!=null) { for (Category c : newShow.getCategories()) { anime.getCategories().add(entityManager.getReference(Category.class, c.getId()); } }