org.hibernate.PersistentObjectException:传递给persist的分离实体:org.hibernate.event.intern中的com.demo.assistlane.domain.FaqArticle

时间:2017-03-01 11:00:13

标签: hibernate spring-data hibernate-mapping

当我点击删除API http://localhost:9999/faqArticles 时,它会发出异常........................... .........

FaqCategory.java

@Data
@Entity
@EqualsAndHashCode(callSuper = false)
@EntityListeners({ AbstractEntityListener.class })
@Audited
public class FaqCategory extends AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "display_name")
    private String displayName;

    private String summary;

    @OneToMany(mappedBy = "faqCategory", cascade = CascadeType.PERSIST, fetch = FetchType.EAGER, orphanRemoval = true)
    private Set<FaqArticle> faqArticle = new HashSet<FaqArticle>();
}

`FaqArticle.java

    @Data
    @Entity
    @EqualsAndHashCode(callSuper = false, exclude = { "faqCategory", "keywords","faqRelatedArticles"})
    @EntityListeners({ AbstractEntityListener.class })
    @ToString(exclude = { "faqCategory", "keywords", "faqRelatedArticles"})
    @Audited
    public class FaqArticle extends AbstractEntity {

        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;

        private String body;

        @ElementCollection(fetch = FetchType.LAZY)
        @CollectionTable(name = "keyword", joinColumns = { @JoinColumn(name = "id") })
        private Set<String> keywords = new HashSet<String>();

        @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
        private Set<FaqArticle> faqRelatedArticles = new HashSet<FaqArticle>();

        @Column(name = "publish")
        private Boolean publish;

        @ManyToOne(fetch = FetchType.LAZY)
        private FaqCategory faqCategory;
    }

` FaqArticleService.java

    @Service
public class FaqArticleService extends AbstractService<FaqArticle, Long> {

    @Autowired
    private FaqArticleRepository faqArticleRepository;

    @Autowired
    private DTOToDomainConverstionService dtoToDomainConverstionService;

    public FaqArticleService(FaqArticleRepository faqArticleRepository) {
        super(faqArticleRepository);
        this.faqArticleRepository = faqArticleRepository;
    }

    public FaqArticle getById(Long id) {
        return faqArticleRepository.findOne(id);
    }

    @Transactional
    public FaqArticle createFaqArticle(FaqArticleDTO faqArticleDTO) {
        FaqArticle faqArticle = dtoToDomainConverstionService.convertFaqArticle(faqArticleDTO);
        return faqArticleRepository.save(faqArticle);
    }

    public Page<FaqArticle> getAllFaqArticle(Pageable pageable) {
        return faqArticleRepository.findAll(pageable);
    }

    public List<FaqArticle> getAllFaqArticle() {
        return faqArticleRepository.findAll();
    }

    @Transactional
    public void deleteFaqArticle(Long id) {
        FaqArticle faqArticle = getById(id);
        faqArticleRepository.delete(faqArticle);
    }

    @Transactional
    public void deleteAllFaqArticle() {
        faqArticleRepository.deleteAll();
    }

}

`    FaqArticleController.java

@RestController
@RequestMapping(value = "/faqArticles")
public class FaqArticleController {

    @Autowired
    private FaqArticleService faqArticleService;

    @Autowired
    private FaqArticleResourceAssembler faqArticleResourseAssembler;

    @Autowired
    private PagedResourcesAssembler<FaqArticle> pagedResourcesAssembler;

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity<PagedResources> getAllFaqArticle(Pageable pageable) {
        Page<FaqArticle> faqArticlePage = faqArticleService.getAllFaqArticle(pageable);
        PagedResources pagedResources = pagedResourcesAssembler.toResource(faqArticlePage, faqArticleResourseAssembler);

        if (faqArticlePage.getContent() == null || faqArticlePage.getContent().isEmpty()) {
            EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
            EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(FaqCategory.class);
            List<EmbeddedWrapper> embedded = Collections.singletonList(wrapper);
            pagedResources = new PagedResources(embedded, pagedResources.getMetadata(),
                    pagedResources.getLinks());
        }
        return new ResponseEntity<PagedResources>(pagedResources, HttpStatus.OK);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ResponseEntity<FaqArticleResource> getFaqArticle(@PathVariable Long id){
        FaqArticle faqArticle = faqArticleService.getById(id);
        FaqArticleResource rsource = faqArticleResourseAssembler.toResource(faqArticle);
        return  new ResponseEntity<FaqArticleResource>(rsource, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.POST)
    public ResponseEntity<FaqArticleResource> saveFaqArticle(@RequestBody FaqArticleDTO faqArticleDTO){
        FaqArticle faqArticle = faqArticleService.createFaqArticle(faqArticleDTO);
        FaqArticleResource rsource = faqArticleResourseAssembler.toResource(faqArticle);
        return  new ResponseEntity<FaqArticleResource>(rsource, HttpStatus.CREATED);
    }

    @RequestMapping(method = RequestMethod.DELETE)
    public ResponseEntity<Void> deleteAllFaqArticle(){
        faqArticleService.deleteAllFaqArticle();
        return ResponseEntity.noContent().build();
    }

    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)
    public ResponseEntity<Void> deleteFaqArticle(@PathVariable Long id){
        faqArticleService.deleteFaqArticle(id);
        return ResponseEntity.noContent().build();
    }
}

application.properties

# server config block
server.port = 9999

# Connection url for the database "netgloo_blog"
spring.datasource.url = jdbc:mysql://localhost:3306/assistlane?createDatabaseIfNotExist=true&verifyServerCertificate=false&useSSL=false&requireSSL=false
spring.datasource.dataSourceClassName=com.mysql.jdbc.Driver

#spring.data.rest.basePath=/api

# Username and password
spring.datasource.username = root
spring.datasource.password = root

# Show or not log for each sql query
spring.jpa.show-sql = true

# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

spring.jpa.properties.org.hibernate.envers.audit_table_suffix=_audit 
spring.jpa.properties.org.hibernate.envers.store_data_at_delete= true

# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

DTOToDomainConverstionService.java

    @Service
public class DTOToDomainConverstionService {

    public FaqCategory convertFAQCategory(FaqCategoryDTO faqCategoryDTO) {

        FaqCategory faqCategory = new FaqCategory();
        Set<FaqArticleDTO> faqArticleDTOs = faqCategoryDTO.getFaqArticleDTO();
        Set<FaqArticle> faqArticles = new HashSet<FaqArticle>();
        for (FaqArticleDTO faqArticleDTO : faqArticleDTOs) {
            FaqArticle faqArticle = new FaqArticle();
            faqArticle.setBody(faqArticleDTO.getBody());
            faqArticle.setPublish(faqArticleDTO.getPublish());
            faqArticle.setKeywords(faqArticleDTO.getKeywords());
            faqArticle.setFaqCategory(faqCategory);
            Set<FaqArticle> subfaqArticles = new HashSet<FaqArticle>();
            for (FaqArticleDTO subfaqArticleDTO : faqArticleDTO.getFaqRelatedArticles()) {
                FaqArticle subfaqArticle = new FaqArticle();
                subfaqArticle.setBody(subfaqArticleDTO.getBody());
                subfaqArticle.setPublish(subfaqArticleDTO.getPublish());
                subfaqArticle.setKeywords(subfaqArticleDTO.getKeywords());
                subfaqArticle.setFaqCategory(faqCategory);
                subfaqArticles.add(subfaqArticle);
            }
            faqArticle.setFaqRelatedArticles(subfaqArticles);
            faqArticles.add(faqArticle);
        }
        faqCategory.setDisplayName(faqCategoryDTO.getDisplayName());
        faqCategory.setSummary(faqCategoryDTO.getSummary());
        faqCategory.setFaqArticle(faqArticles);
        return faqCategory;
    }

    public FaqArticle convertFaqArticle(FaqArticleDTO faqArticleDTO) {

        FaqArticle faqArticle = new FaqArticle();
        faqArticle.setBody(faqArticleDTO.getBody());
        faqArticle.setPublish(faqArticleDTO.getPublish());
        faqArticle.setKeywords(faqArticleDTO.getKeywords());
        /*Set<FaqArticle> subfaqArticles = new HashSet<FaqArticle>();
        for (FaqArticleDTO subfaqArticleDTO : faqArticleDTO.getFaqRelatedArticles()) {
            FaqArticle subfaqArticle = new FaqArticle();
            subfaqArticle.setBody(subfaqArticleDTO.getBody());
            subfaqArticle.setPublish(subfaqArticleDTO.getPublish());
            subfaqArticle.setKeywords(subfaqArticleDTO.getKeywords());
            subfaqArticles.add(subfaqArticle);
        }
        faqArticle.setFaqRelatedArticles(subfaqArticles);*/
        return faqArticle;
    }
}

1 个答案:

答案 0 :(得分:0)

您应该将faqCategory上的FaqArticle属性显式设置为null。

如果您确实希望将值设置为非空值,则应确保在活动会话的边界​​内获取相应的FaqArticle,以便在保存时保留实例不会分离新FaqArticle以避免此失败。