Spring Data JPA @OneToOne注释无限递归错误

时间:2017-08-20 15:23:25

标签: spring hibernate jpa

Husband.java

package com.example.demo.com.example.domain;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

import javax.persistence.*;


//@Data
//@NoArgsConstructor
//@EqualsAndHashCode
//@ToString
@Entity
@Table(name = "t_husban")
public class Husband {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private String job;

    @OneToOne
    @JoinColumn(name = "wife_fk",referencedColumnName = "id")
    private Wife wife;

    //omitted getter/setter
}

Wife.java

package com.example.demo.com.example.domain;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

import javax.persistence.*;

//@Data
//@NoArgsConstructor
@EqualsAndHashCode(exclude = "husband",callSuper = false)
@Entity
@Table(name = "t_wife")
public class Wife {

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

    private String name;

    @OneToOne(mappedBy = "wife",cascade = {CascadeType.ALL})
    private Husband husband;

    //omitted getter/setter
}

Service.java

@Service

    public class TestOneToOneEitherSide {

        @Autowired
        private WifeRepository wifeDao;

        @Autowired
        private HusbandRepository husbandDao;
        public Husband testCreate() {

            Husband husband = husbandDao.findByName("Wang");
            return husband;
        }
    }

当我使用spring数据jpa从数据库查询丈夫时,它会在结果中发生无限递归,看到下面的图片。使用@OneToOne注释时出了什么问题?有人能给我一些建议吗?或者我以错误的方式使用注释。

the picture

3 个答案:

答案 0 :(得分:2)

这是一个已知的问题,当你有双向关系时,jackson将尝试序列化另一侧的每一个引用,以便它具有无限递归的逻辑。

解决方案:有很多解决方案,您可以在一侧使用@JsonIgnore以避免序列化带注释的引用,从而打破无限递归

@EqualsAndHashCode(exclude = "husband",callSuper = false)
@Entity
@Table(name = "t_wife")
@JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, property="@id")
public class Wife {

@JsonIdentityInfo(generator=ObjectIdGenerators.UUIDGenerator.class, property="@id")
@Entity
@Table(name = "t_husban")
public class Husband {
@Id

你也可以使用@JsonManagedReference / @JsonBackReference,检查这个link以获取更多信息如何使用它们

这个答案有一个问题,如果你试图序列化妻子的方向你不会有丈夫的对象,因为解决方案是避免序列化。

有一个很好的解决方案,它在这个link中提到,想法是生成对父实体的引用,所以如果你序列化丈夫,你将有丈夫 - >妻子 - &gt ; [引用丈夫而不是丈夫],你需要做的就是用@JsonIdentityInfo注释你的实体

import { fetchPosts  } from '../actions';
import React, {Component} from 'react';
import {bindActionCreators, dispatch} from 'redux';
import {connect} from 'react-redux';
import PropTypes  from 'prop-types';
import map from 'lodash/fp/map';
import flatten from 'lodash/fp/flatten';
import sortBy from 'lodash/fp/sortBy';
import compose from 'lodash/fp/compose';
import take from 'lodash/fp/take';
import _ from 'lodash';


class PostsIndex extends Component {

state = {
    posts: []
};

    componentDidMount() {

        this.props.fetchPosts();


    }

    displayPosts () {
        //console.log(post) works, console.log(post.title) returns undefined.
        return  _.map(this.props.posts, (post)=>{debugger;console.log(post.title);});
    }

    render() {
        if(this.props.posts.length === 0) {
            return (<div>Loading...</div>);
        }
        return (<ul>{this.displayPosts()}</ul>);
    }
}

function mapStateToProps(state) {
    return {
        posts: (state.posts) ? state.posts : []
    };
}

function mapDispatchToProps (dispatch) {
    return  bindActionCreators({fetchPosts: fetchPosts}, dispatch);
   }

export default connect(mapStateToProps, mapDispatchToProps)(PostsIndex);

答案 1 :(得分:1)

您应该对拥有实体使用@JsonBackReference,对包含实体类的子代使用@JsonManagedReference。

@JsonManagedReference
@Onetoone
private Queue queues;



    @Onetoone
    @JoinColumn(name = "qid")
   // @JsonIgnore
    @JsonBackReference
    private Queue_group queue_group;

答案 2 :(得分:0)

可以在丈夫字段或妻子字段上使用lombok的@ToString.Exclude来打破循环引用,要么jackson会尝试无限地来回序列化每个引用。

@OneToOne(mappedBy = "wife",cascade = {CascadeType.ALL})
@ToString.Exclude
private Husband husband;

@OneToOne
@JoinColumn(name = "wife_fk",referencedColumnName = "id")
@ToString.Exclude
private Wife wife;