首页 > 解决方案 > @OneToMany 和 @ManyToOne 双向链接时关联实体的保存不正确

问题描述

我不明白为什么这么多额外的记录会保存到父表中。可能是什么问题?

@Entity
@Table(name ="posts")
public class Post {

    @Id
    @SequenceGenerator(name = "jpaSequence.Post",
            sequenceName = "SEQUENCE_POST",
            allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jpaSequence.Post")
    private Long id;
    private String subject;

    @OneToMany(mappedBy = "post", cascade = {CascadeType.ALL})
    private List<Comment> comments = new ArrayList<>();

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private User user;


    public Post() {
    }

@Entity
@Table(name = "comments")
public class Comment {

    @Id
    @SequenceGenerator(name = "jpaSequence.Comment",
            sequenceName = "SEQUENCE_COMMENT",
            allocationSize = 1, initialValue = 4)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jpaSequence.Comment")
    private Long id;

    private String reply;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn
    private Post post;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private User user;


    public Comment() {
    }

@Entity
@Table(name = "users")
public class User {

    @Id
    @SequenceGenerator(name = "jpaSequence.User",
            sequenceName = "SEQUENCE_USER",
            allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jpaSequence.User")
    private Long id;

    private String name;
    private String email;

    public User() {
    }

json

{
    "id": null,
    "subject": "JPA Entity Graph - saved new",
    "comments": [
        {
            "id": null,
            "reply": "new techology !!",
            "post": {
                "id": null
            },
            "user": {
                "id": 2,
                "name": "user2",
                "email": "user2@test.com"
            }
        },
        {
            "id": null,
            "reply": "new techology and good tecnology !!",
            "post": {
                "id": null
            },
            "user": {
                "id": 3,
                "name": "user3",
                "email": "user3@test.com"
            }
        }
    ],
    "user": {
        "id": 1,
        "name": "user1",
        "email": "user1@test.com"
    }
}

在此处输入图像描述

也许在儿童记录方面,我该如何限制这种循环?

更新 1

@Service
public class PostSaveServiceImpl implements PostSaveService{

    private PostRepository repository;

    private PostWithoutNestedLevelsTransformers transformer;

    @Autowired
    public PostSaveServiceImpl(PostRepository repository,
                               PostWithoutNestedLevelsTransformers transformer) {
        this.repository = repository;
        this.transformer = transformer;
    }


    @Transactional
    @Override
    public PostDto setData(PostDto dto) {

        Post post = this.transformer.transformDtoToEntity(dto);

        Post postSaved = saveData(post);

        PostDto postDto = this.transformer.transformEntityToDto(postSaved);

        return postDto;
    }

    private Post saveData(Post post){

        Post save = this.repository.save(post);

        return save;
    }


    @Transactional
    @Override
    public Iterable<PostDto> setListData(Iterable<PostDto> listDto) {
        return null;
    }
}

public interface PostRepository extends CrudRepository<Post, Long> {

    @EntityGraph(attributePaths = {
            "comments",
            "user"
    })
    Optional<Post> findById(Long id);
}

如果我删除{CascadeType.ALL}在实体子的一边,我得到

{
    "id": 71,
    "subject": "JPA Entity Graph - saved new",
    "comments": [
        {
            "id": null,
            "reply": "new techology !!",
            "post": null,
            "user": {
                "id": 2,
                "name": "user2",
                "email": "user2@test.com"
            }
        },
        {
            "id": null,
            "reply": "new techology and good tecnology !!",
            "post": null,
            "user": {
                "id": 3,
                "name": "user3",
                "email": "user3@test.com"
            }
        }
    ],
    "user": {
        "id": 1,
        "name": "user1",
        "email": "user1@test.com"
    }
}

评论不会写。

在此处输入图像描述

在此处输入图像描述

如果我放的话,在实体孩子的一边

   @ManyToOne(fetch = FetchType.LAZY, cascade = {
            CascadeType.MERGE,
            CascadeType.PERSIST
    })

,我明白了

在此处输入图像描述

在此处输入图像描述

14-04-2020 11:25:13.740 DEBUG 27144   org.hibernate.SQL                        : 
    select
        sequence_post.nextval 
    from
        dual
 14-04-2020 11:25:13.746 DEBUG 27144   o.h.id.enhanced.SequenceStructure        : Sequence value obtained: 75
 14-04-2020 11:25:13.746 DEBUG 27144   o.h.r.j.i.ResourceRegistryStandardImpl   : HHH000387: ResultSet's statement was not registered
 14-04-2020 11:25:13.747 DEBUG 27144   o.h.e.i.AbstractSaveEventListener        : Generated identifier: 75, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
 14-04-2020 11:25:13.760 DEBUG 27144   org.hibernate.SQL                        : 
    select
        sequence_comment.nextval 
    from
        dual
 14-04-2020 11:25:13.822 DEBUG 27144   o.h.id.enhanced.SequenceStructure        : Sequence value obtained: 42
 14-04-2020 11:25:13.822 DEBUG 27144   o.h.r.j.i.ResourceRegistryStandardImpl   : HHH000387: ResultSet's statement was not registered
 14-04-2020 11:25:13.822 DEBUG 27144   o.h.e.i.AbstractSaveEventListener        : Generated identifier: 42, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
 14-04-2020 11:25:13.822 DEBUG 27144   org.hibernate.SQL                        : 
    select
        sequence_post.nextval 
    from
        dual
 14-04-2020 11:25:13.823 DEBUG 27144   o.h.id.enhanced.SequenceStructure        : Sequence value obtained: 76
 14-04-2020 11:25:13.823 DEBUG 27144   o.h.r.j.i.ResourceRegistryStandardImpl   : HHH000387: ResultSet's statement was not registered
 14-04-2020 11:25:13.823 DEBUG 27144   o.h.e.i.AbstractSaveEventListener        : Generated identifier: 76, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
 14-04-2020 11:25:13.824 DEBUG 27144   org.hibernate.SQL                        : 
    select
        sequence_comment.nextval 
    from
        dual
 14-04-2020 11:25:13.826 DEBUG 27144   o.h.id.enhanced.SequenceStructure        : Sequence value obtained: 43
 14-04-2020 11:25:13.827 DEBUG 27144   o.h.r.j.i.ResourceRegistryStandardImpl   : HHH000387: ResultSet's statement was not registered
 14-04-2020 11:25:13.827 DEBUG 27144   o.h.e.i.AbstractSaveEventListener        : Generated identifier: 43, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
 14-04-2020 11:25:13.827 DEBUG 27144   org.hibernate.SQL                        : 
    select
        sequence_post.nextval 
    from
        dual
 14-04-2020 11:25:13.828 DEBUG 27144   o.h.id.enhanced.SequenceStructure        : Sequence value obtained: 77
 14-04-2020 11:25:13.828 DEBUG 27144   o.h.r.j.i.ResourceRegistryStandardImpl   : HHH000387: ResultSet's statement was not registered
 14-04-2020 11:25:13.828 DEBUG 27144   o.h.e.i.AbstractSaveEventListener        : Generated identifier: 77, using strategy: org.hibernate.id.enhanced.SequenceStyleGenerator
 14-04-2020 11:25:13.828 TRACE 27144   o.s.t.i.TransactionInterceptor           : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
 14-04-2020 11:25:13.828 TRACE 27144   o.s.t.i.TransactionInterceptor           : Completing transaction for [com.web.service.save.post.impl.PostSaveServiceImpl.setData]
 14-04-2020 11:25:13.829 DEBUG 27144   o.h.e.t.internal.TransactionImpl         : committing
 14-04-2020 11:25:13.829 DEBUG 27144   o.h.e.i.AbstractFlushingEventListener    : Processing flush-time cascades
 14-04-2020 11:25:13.830 DEBUG 27144   o.h.e.i.AbstractFlushingEventListener    : Dirty checking collections
 14-04-2020 11:25:13.833 DEBUG 27144   o.hibernate.engine.internal.Collections  : Collection found: [com.dao.domain.post.Post.comments#75], was: [<unreferenced>] (initialized)
 14-04-2020 11:25:13.833 DEBUG 27144   o.hibernate.engine.internal.Collections  : Collection found: [com.dao.domain.post.Post.comments#76], was: [<unreferenced>] (initialized)
 14-04-2020 11:25:13.833 DEBUG 27144   o.hibernate.engine.internal.Collections  : Collection found: [com.dao.domain.post.Post.comments#77], was: [<unreferenced>] (initialized)
 14-04-2020 11:25:13.834 DEBUG 27144   o.h.e.i.AbstractFlushingEventListener    : Flushed: 5 insertions, 0 updates, 0 deletions to 5 objects
 14-04-2020 11:25:13.834 DEBUG 27144   o.h.e.i.AbstractFlushingEventListener    : Flushed: 3 (re)creations, 0 updates, 0 removals to 3 collections
 14-04-2020 11:25:13.834 DEBUG 27144   o.hibernate.internal.util.EntityPrinter  : Listing entities:
 14-04-2020 11:25:13.834 DEBUG 27144   o.hibernate.internal.util.EntityPrinter  : com.dao.domain.post.Post{comments=[], subject=null, id=76, user=null}
 14-04-2020 11:25:13.834 DEBUG 27144   o.hibernate.internal.util.EntityPrinter  : com.dao.domain.post.Post{comments=[], subject=null, id=77, user=null}
 14-04-2020 11:25:13.834 DEBUG 27144   o.hibernate.internal.util.EntityPrinter  : com.dao.domain.comment.Comment{post=com.dao.domain.post.Post#77, id=43, reply=new techology and good tecnology !!, user=com.dao.domain.users.User#3}
 14-04-2020 11:25:13.834 DEBUG 27144   o.hibernate.internal.util.EntityPrinter  : com.dao.domain.post.Post{comments=[com.dao.domain.comment.Comment#42, com.dao.domain.comment.Comment#43], subject=JPA Entity Graph - saved new, id=75, user=com.dao.domain.users.User#1}
 14-04-2020 11:25:13.835 DEBUG 27144   o.hibernate.internal.util.EntityPrinter  : com.dao.domain.comment.Comment{post=com.dao.domain.post.Post#76, id=42, reply=new techology !!, user=com.dao.domain.users.User#2}
 14-04-2020 11:25:13.839 DEBUG 27144   org.hibernate.SQL                        : 
    insert 
    into
        posts
        (subject, user_id, id) 
    values
        (?, ?, ?)
 14-04-2020 11:25:13.839 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [JPA Entity Graph - saved new]
 14-04-2020 11:25:13.840 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [1]
 14-04-2020 11:25:13.840 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [BIGINT] - [75]
 14-04-2020 11:25:13.842 DEBUG 27144   org.hibernate.SQL                        : 
    insert 
    into
        posts
        (subject, user_id, id) 
    values
        (?, ?, ?)
 14-04-2020 11:25:13.842 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [null]
 14-04-2020 11:25:13.842 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [null]
 14-04-2020 11:25:13.842 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [BIGINT] - [76]
 14-04-2020 11:25:13.844 DEBUG 27144   org.hibernate.SQL                        : 
    insert 
    into
        comments
        (post_id, reply, user_id, id) 
    values
        (?, ?, ?, ?)
 14-04-2020 11:25:13.844 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [76]
 14-04-2020 11:25:13.844 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [new techology !!]
 14-04-2020 11:25:13.844 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [BIGINT] - [2]
 14-04-2020 11:25:13.844 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [BIGINT] - [42]
 14-04-2020 11:25:13.845 DEBUG 27144   org.hibernate.SQL                        : 
    insert 
    into
        posts
        (subject, user_id, id) 
    values
        (?, ?, ?)
 14-04-2020 11:25:13.845 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [null]
 14-04-2020 11:25:13.845 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [null]
 14-04-2020 11:25:13.845 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [BIGINT] - [77]
 14-04-2020 11:25:13.847 DEBUG 27144   org.hibernate.SQL                        : 
    insert 
    into
        comments
        (post_id, reply, user_id, id) 
    values
        (?, ?, ?, ?)
 14-04-2020 11:25:13.847 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [77]
 14-04-2020 11:25:13.847 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [new techology and good tecnology !!]
 14-04-2020 11:25:13.847 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [BIGINT] - [3]
 14-04-2020 11:25:13.847 TRACE 27144   o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [BIGINT] - [43]
 14-04-2020 11:25:13.857 DEBUG 27144   o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [*/*] and supported [application/json]
 14-04-2020 11:25:13.866 DEBUG 27144   o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [PostDto{id=75, subject='JPA Entity Graph - saved new', comments=[CommentDto{id=42, reply='new techol (truncated)...]
 14-04-2020 11:25:13.878 DEBUG 27144   o.s.web.servlet.DispatcherServlet        : Completed 200 OK

但是我在父表中获得了带有空字段的额外条目。谁知道这里有什么问题?

标签: javaspring-data-jpahibernate-mapping

解决方案


在评论表上,为什么需要 cascadeType 为 ALL

CascadeType 意味着 - Comment 上发生的任何更改也必须级联到 Post。

尝试删除它

@Entity
@Table(name = "comments")
public class Comment {

    @Id
    @SequenceGenerator(name = "jpaSequence.Comment",
            sequenceName = "SEQUENCE_COMMENT",
            allocationSize = 1, initialValue = 4)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "jpaSequence.Comment")
    private Long id;

    private String reply;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private Post post;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn
    private User user;


    public Comment() {
    } 

推荐阅读