Hibernate无限递归和双向关系

问题描述 投票:0回答:3

我有两个实体。我想要项目和任务之间存在双向关系。

  • 一个项目有一个或多个任务
  • 一项任务仅与一个项目相关联

这是我的实体:


ProjectEntity.java

@Entity
@Table(name = "projects")
public class ProjectEntity {
    @Id
    @GeneratedValue
    @Column(name = "pr_id")
    private long id;

    @Column(name = "pr_name", nullable = false)
    private String name;

    @OneToMany(cascade=CascadeType.ALL, mappedBy="project",orphanRemoval=true)
    @JsonBackReference
    private Set<TaskEntity> tasks = new HashSet<TaskEntity>();

   // Getters, constructors, setters

TaskEntity.java

@Entity
@Table(name = "tasks")
public class TaskEntity {
    @Id
    @GeneratedValue
    @Column(name = "ta_id")
    private long id;

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

    @ManyToOne
    @JoinColumn(name="pr_id")
    @JsonManagedReference
    private ProjectEntity project;

    // Getters, constructors, setters

我希望在每个

ProjectEntity
中都有任务列表,以及在每个
TaskEntity
中关联的项目。

在这里,我使用

@JsonManagedReference
@JsonBackReference
来停止它生成的无限递归,但在我的
ProjectEntity
中,我没有任务列表(因为
@JsonBackReference
)...

你能帮我找回

ProjectEntity
中的任务列表吗?我听说过
@JsonIdentifyInfo
,但我还没有成功。

希望我能理解:)

java hibernate jackson
3个回答
5
投票

我知道的解决方案实际上是使用“@JsonIdentityInfo”而不是“@JsonBackReference”和“@JsonManagedReference”。 您必须删除“@JsonBackReference”和“@JsonManagedReference”才能使用“@JsonIdentityInfo”。

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id")
@Entity
@Table(name = "projects")
public class ProjectEntity {
    @Id
    @GeneratedValue
    @Column(name = "pr_id")
    private long id;

    @Column(name = "pr_name", nullable = false)
    private String name;

    @OneToMany(cascade=CascadeType.ALL, mappedBy="project",orphanRemoval=true)
    private Set<TaskEntity> tasks = new HashSet<TaskEntity>();
}


@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id")
@Entity
@Table(name = "tasks")
public class TaskEntity {
    @Id
    @GeneratedValue
    @Column(name = "ta_id")
    private long id;

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

    @ManyToOne
    @JoinColumn(name="pr_id")
    private ProjectEntity project;
}

2
投票

您可以选择为列表 ProjectEntity.tasks 实现自定义序列化器。但您必须在某个时刻控制/停止序列化周期;这将取决于您的要求。 这是我的意思的一个例子。

@Entity
@Table(name = "projects")
public class ProjectEntity {
    ...
    @OneToMany(cascade=CascadeType.ALL, mappedBy="project", orphanRemoval=true)
    @JsonSerialize(using = CustomListSerializer.class)
    private Set<TaskEntity> tasks = new HashSet<TaskEntity>();
}

CustomListSerializer 可能是这样的,

public class CustomListSerializer extends JsonSerializer<List<TaskEntity>>{

    @Override
    public void serialize(List<TaskEntity> tasks, JsonGenerator generator, SerializerProvider provider)
          throws IOException, JsonProcessingException {

        generator.writeStartArray();

        for (TaskEntity task : tasks) {
            generator.writeStartObject("taskEntity")
                .write("id", task.id)
                .write("name", task.name)
                .write("project", task.project.id) //<- here you stop the cycle 
            .writeEnd();
        }
        generator.writeEnd();
    }
}

请注意,它基本上是提到的迷你指南的示例,但它序列化了项目任务列表元素的信息,而不仅仅是任务的ID。


0
投票

当您使用双向关系时需要记住以下几点:

1.直接在表示层中使用实体会导致 Hibernate HttpMessageNotWritableException - 使用 DTO 解决了这个问题 - 检查这里

  1. 如果您在相关实体上使用 lombok @Data 注释,则 toString() 自动生成方法存在循环依赖问题 - 在此处检查
© www.soinside.com 2019 - 2024. All rights reserved.