使用@OneToOne批注保存外键时出现问题另存为空

问题描述

我有两个实体(ProjectOtherData)和一个抽象实体。我正在使用MySQL和Quarkus框架。

问题::当我尝试保存Project实体字段时,project_id仍然是null

表架构:

table "projects"


table "project_other_data"


下一张照片显示了“ project_other_data”表中的fk约束:

enter image description here

抽象实体

@MappedSuperclass
public class AbstractEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;

    // getters and setters
}

项目实体

@Entity
@Table(name = "projects")
public class Project extends AbstractEntity {

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

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

    @Column(name = "date_create")
    @JsonbDateFormat(value = "yyyy-MM-dd")
    private LocalDate dateCreate;

    @Column(name = "date_update")
    @JsonbDateFormat(value = "yyyy-MM-dd")
    private LocalDate dateUpdate;

    @OneToOne(mappedBy = "project",cascade = CascadeType.ALL)
    private OtherData otherData;

    // getters and setters
}

OtherData实体

@Entity
@Table(name = "project_other_data")
public class OtherData extends AbstractEntity {

    @OneToOne
    @JoinColumn(name = "project_id")
    private Project project;

    @Column(name = "days_in_year")
    private Integer daysInYear;

    @Column(name = "holidays_in_year")
    private Integer holidaysInYear;

    @Column(name = "weeks_in_year")
    private Integer weeksInYear;

    @Column(name = "free_saturdays")
    private Integer freeSaturdays;

    @Column(name = "downtime_coefficient")
    private BigDecimal downtimeCoefficient;

    @Column(name = "changes")
    private Integer changes;

    // getters and setters
}

使用代码保存实体:

@Path("projects")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProjectRest {

    @Inject
    ProjectService projectService;

    @POST
    public Response saveProject(Project project) {
        return Response.ok(projectService.saveProject(project)).build();
    }
}
@RequestScoped
@Transactional
public class ProjectService {

    @Inject
    EntityManager entityManager;

    public Project saveProject(Project project) {

        if (project.getId() == null) {
            entityManager.persist(project);
        } else {
            entityManager.merge(project);
        }

        return project;
    }
}

解决方法

通过POST嵌入了Project的新OtherData,我得以重现该问题。我用于POST的正文:

{
    "name": "John","surname": "Doe","otherData": {}
}

要点是:数据库实体也用作DTO。因此,project中用于请求正文的字段otherData设置为null(因为没有传递任何Project,这将是递归的无限定义)。

在处理从其余控制器到服务再到存储库的实体期间,project中的otherData从未设置。一种快速解决方案是按以下方式修改ProjectService::saveProject

public Project saveProject(Project project) {
    project.getOtherData().setProject(project); // This line was added
    if (project.getId() == null) {
        entityManager.persist(project);
    } else {
        entityManager.merge(project);
    }

    return project;
}

这将解决数据库问题(将设置project_id),但会导致下一个问题。由于出现

,响应正文无法序列化

org.jboss.resteasy.spi.UnhandledException:javax.ws.rs.ProcessingException:RESTEASY008205:JSON绑定序列化错误javax.json.bind.JsonbException:无法从com.nikitap.org_prod.entities序列化属性'otherData' 。项目

...

由于:javax.json.bind.JsonbException:在类com.nikitap.org_prod.entities.Project中找到了递归引用。

对象结构是循环的(project引用otherData,返回引用project,...),杰克逊无法解决此循环。

要解决此问题,我建议将DTO和数据库实体分开,并在它们之间显式映射。本质上:

  • 以非循环顺序构造Dto对象以表示您希望接收的JSON-Request和-Response
  • 将与JSON相关的注释从数据库实体类传输到DTO类
  • 在服务层或存储层(您的选择)中,将DTO映射到数据库实体,设置所有字段(包括从projectotherData的引用,反之亦然)
  • 在同一层中,将数据库实体映射回非循环DTO
  • 从REST端点返回DTO

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...