【问题标题】:JPA - ManyToOne & OneToMany strackoverflow exceptionJPA - ManyToOne 和 OneToMany 堆栈溢出异常
【发布时间】:2021-08-31 11:21:34
【问题描述】:

我有一个简单的模型,其中包含 EmployeeCompany 对象。

我们的目标是简单地获得一份员工名单及其所在公司的名单,以及一份公司名单及其员工。

代码属于抛出无限递归调用(stackloverflow)引起的异常。由于一个关系 EARGLY 和其他 LAZYLY 获取关系,我无法理解它发生的原因。获取哪些数据(Company.findAll 或 Employee.findAll)并不重要

这是我项目中使用的数据库和实体配置:

关系是:

ONE Company has MANY Employees.
MANY Employees have (work for) ONE Company 

所有者方是 Employee(它是对 Company 具有 FK 的表),基于这样的想法:“没有公司就没有员工,但相反的情况可能是真的”。

我理解实体所有权的方式是这样的: Employee 拥有关系,所以,当我们 fecth employee 数据时,它也会获取它所属的 company (ManyToOne),但是当我们 fecth company > 数据,员工(OneToMany)将不会被获取。

员工实体类:

@Entity
@Table(name = "employee")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EmployeeEntity {

   @Id
   @Column(name = "id")
   private Long id;

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

   @ManyToOne
   @JoinColumn(name = "company_id", nullable = false)
   private CompanyEntity company;
}

公司实体类:

@Entity
@Table(name = "company")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CompanyEntity {

@Id
@Column(name = "id")
private Long id;

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

@OneToMany(mappedBy = "company")
private Set<EmployeeEntity> employees = new HashSet<>();
}

表格:

CREATE TABLE Company (
    id INT NOT NULL,
    name VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE Employee (
    id INT NOT NULL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    company_id INT NOT NULL,
);

ALTER TABLE Employee
    ADD FOREIGN KEY (company_id)
    REFERENCES company (id);

最终目标是让它在两个方面都发挥作用。

【问题讨论】:

    标签: java hibernate jpa one-to-many many-to-one


    【解决方案1】:

    如果有引发异常的示例代码会很好。我猜是因为你在那里有 lombok @Data 注释(其中还生成 toString),如果你尝试记录这些实体的一些实例,它会延迟加载另一个引用的实体,然后返回另一个在无限循环中。

    所以你可以尝试删除@Data注解,看看是否有帮助。

    【讨论】:

    • 我知道你的意思,但这次不是 lombook 导致... stackkoverflow 发生在获取时间,而不是当我尝试使用(toString、equals 或 hashcode)实体时.
    【解决方案2】:

    使用@JsonManagedReference@JsonBackReference。 问题是他们正在互相获取。你得到一个Employee 和他,他的Company,然后Company 获取它的Employees,然后它的Employees 他们的Companies 等等......

    检查this

    以这种方式更改代码:

    @Entity
    @Table(name = "employee")
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class EmployeeEntity {
    
       @Id
       @Column(name = "id")
       private Long id;
    
       @Column(name = "name")
       private String name;
    
    
       @JsonManagedReference // <--------------
       @ManyToOne
       @JoinColumn(name = "company_id", nullable = false)
       private CompanyEntity company;
    }
    

    @Entity
    @Table(name = "company")
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class CompanyEntity {
    
    @Id
    @Column(name = "id")
    private Long id;
    
    @Column(name = "name")
    private String name;
    
    @JsonBackReference // <--------------
    @OneToMany(mappedBy = "company")
    private Set<EmployeeEntity> employees = new HashSet<>();
    }
    

    @JsonManagedReference 是引用的前向部分——那个 可以正常序列化。 @JsonBackReference 是后面部分 参考 - 它将从序列化中省略。

    【讨论】:

    • 成功了。你能解释一下 Jackson 注释在实体级别是如何工作的吗?我的意思是,我没有序列化这些实体(至少不明确)。我希望 javax.persistence.* 在这个级别上解决它。
    • 当您获取 (GET) 时,您很可能会返回一个包含所有员工的 JSON 数组,或者即使您只得到一个,实体也会被序列化,对吧?哪里抛出异常?
    • 正如我所说,我没有明确地对其进行序列化,如果它以某种方式通过 JPA 在幕后发生,我想理解。只要实体从@Repository 类返回,我就可以设置异常(在调试模式下)。
    • 你的意思是在你调用 getAll 函数之后吗?您能否将这部分代码添加到您的问题中?
    【解决方案3】:

    解决方案:

    让我看到这个的评论是@haki 的评论。

    问题是由关系的非所有者方的 equals/hashcode 引起的递归调用引起的。

    我会说关于 ManyToOne/OneToMany 关系的经验法则是要么忽略非所有者侧类(在本例中为 EmployeeEntity 类中的 CompanyEntity 字段)上的 equals/hashcode,要么考虑实施它们只有一层深。

    @Entity
    @Table(name = "employee")
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class EmployeeEntity {
    
       @Id
       @Column(name = "id")
       private Long id;
    
       @Column(name = "name")
       private String name;
    
       @ManyToOne
       @JoinColumn(name = "company_id", nullable = false)
       @ToString.Exclude
       @EqualsAndHashCode.Exclude
       private CompanyEntity company;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-05-28
      • 2010-11-27
      • 2020-07-05
      • 1970-01-01
      • 2016-11-14
      • 1970-01-01
      • 2016-02-19
      相关资源
      最近更新 更多