首页 > 解决方案 > 分离的实体传递给持久化java spring

问题描述

因此,当我尝试在我的 spring 应用程序中执行更新方法时,我遇到了一个很大的错误,问题是关于 Caracter 类,因为那似乎是生成它的那个。当我在 main 中设置我的东西并尝试更新数据库中的 Anime 对象时,Caracter 类给了我下面出现的错误

编码

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);

        };
    }
}

和错误


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

标签: javaspringspring-boothibernate

解决方案


我认为这里的问题是,您正在用新集合替换字符集合,并且该集合具有与持久性上下文不同的对象,尽管它使用相同的主键。由于您正在级联更改,Hibernate 尝试刷新更改并意识到该主键的实体已经与持久性上下文相关联并且无法刷新您看到的异常。如果您只想将实体应用于数据库,请尝试在entityManager.merge不先加载实体的情况下使用。或者,您也可以尝试像这样应用集合:

    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());
        }
    }

推荐阅读