代码之家  ›  专栏  ›  技术社区  ›  MrD

Springboot CascadeType所有vs合并和分离的实体

  •  0
  • MrD  · 技术社区  · 7 年前

    我有以下实体:

    @Entity
    @Getter @Setter @NoArgsConstructor @RequiredArgsConstructor
    public class Link extends Auditable {
    
        @Id
        @GeneratedValue
        private Long id;
    
        @NonNull
        private String title;
    
    
        @NonNull
        private String url;
    
        @OneToMany(cascade = CascadeType.ALL, mappedBy = "link")
        private List<Comment> comments = new ArrayList<>();
    
        @Transient
        @Setter(AccessLevel.NONE)
        private String userAlias ;
    
        public String getUserAlias() {
    
            if(user == null)
                return "";
    
            return user.getAlias();
    
    
        }
    
        @ManyToOne
        private User user;
    
        public Long getUser() {
            if(user == null)
                return -1L;
    
            return user.getId();
        }
    
        public void addComment(Comment c) {
            comments.add(c);
            c.setLink(this);
    
        }
    
    
    
    
    }
    
    @Entity
    @Getter @Setter @NoArgsConstructor @RequiredArgsConstructor
    public class Comment extends Auditable{
    
        @Id
        @GeneratedValue
        private Long id;
    
        @NonNull
        private String comment;
    
        @ManyToOne(fetch = FetchType.LAZY)
        private Link link;
    
        public Long getLink() {
            return link.getId();
        }
    
    
    }
    

    如果我创建了一个注释和一个链接,请将该链接与注释关联,然后保存该链接。

    如:

    Link link = new Link("Getting started", "url");
    Comment c = new Comment("Hello!");
    link.addComment(c);
    linkRepository.save(link);
    

    但是,如果我先保存注释:

    Link link = new Link("Getting started", "url");
    Comment c = new Comment("Hello!");
    commentRepository.save(c);
    link.addComment(c);
    linkRepository.save(link);
    

    我得到

    Caused by: org.hibernate.AnnotationException: @OneToOne or @ManyToOne on uk.me.dariosdesk.dariodemo.domain.Comment.link references an unknown entity: uk.me.dariosdesk.dariodemo.domain.Link
        at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:97) ~[hibernate-core-5.4.0.Final.jar:5.4.0.Final]
        at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1815) ~[hibernate-core-5.4.0.Final.jar:5.4.0.Final]
        at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1759) ~[hibernate-core-5.4.0.Final.jar:5.4.0.Final]
        at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1646) ~[hibernate-core-5.4.0.Final.jar:5.4.0.Final]
        at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:287) ~[hibernate-core-5.4.0.Final.jar:5.4.0.Final]
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:903) ~[hibernate-core-5.4.0.Final.jar:5.4.0.Final]
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:934) ~[hibernate-core-5.4.0.Final.jar:5.4.0.Final]
    

    将级联类型从all更改为merge似乎可以解决问题并接受这两种实现。(即:添加预先存在的注释或同时创建注释,然后通过链接保存)

    1)为什么? 2)在使用merge而不是all时,我有什么需要注意的吗?

    0 回复  |  直到 7 年前
        1
  •  1
  •   Peter Å ály    7 年前

    存储库保存方法检查实体是否存在。对于调用新实体persist,对于调用持久实体merge。

    @Transactional
    public <S extends T> S save(S entity) {
    
        if (entityInformation.isNew(entity)) {
            em.persist(entity);
            return entity;
        } else {
            return em.merge(entity);
        }
    }
    

    在第二个用例中,链接是新的实体,因此调用persist()。使用cascadeType.all persist()将层叠到注释实体。注释已被持久化,需要合并,persist()失败。

    如果使用cascadeType.merge persist(),则不会级联到comment。它不会失败。