空外键(Springboot、Hibernate、Postman)

Posted

技术标签:

【中文标题】空外键(Springboot、Hibernate、Postman)【英文标题】:Null Foreign Key (Springboot, Hibernate, Postman) 【发布时间】:2020-11-25 13:51:47 【问题描述】:

我正在使用带有 Hibernate 的 Springboot,我想使用 POST 请求将新的“帖子”保存到我的数据库。我想强调的一件事是我正在使用依赖项“spring-boot-starter-data-rest”。

数据库架构(mysql):

班级用户:

@Entity
@Table(name="user")
public class User implements Serializable 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id", nullable = false)
    public int id;

    @OneToMany(mappedBy = "user_id_fk")
    public Set<Post> posts;

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

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

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

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

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

    @Column(name="create_time")
    protected Date createTime;

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

    public User() 
        this.createTime = new java.util.Date();
    

    public User(String email, String username, String password, String firstName, String lastName, Date createTime, String accountType) 
        this.email = email;
        this.username = username;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.createTime = createTime;
        this.accountType = accountType;
        this.createTime = new java.util.Date();
    

    public User(int id, String email, String username, String password, String firstName, String lastName, Date createTime, String accountType) 
        this.id = id;
        this.email = email;
        this.username = username;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.createTime = createTime;
        this.accountType = accountType;
        this.createTime = new java.util.Date();
    

加上Getters & Setters & toString()。

班级帖子:

@Entity
@Table(name="post")
public class Post implements Serializable 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    public int id;

    @ManyToOne(optional = false)
    @JoinColumn(name = "user_id_fk", nullable = false)
    public User user_id_fk;

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

    @Column(name="likes")
    private int likes;

    @Column(name="dislike")
    private int dislike;

    @Column(name="create_time")
    protected Date createTime;

    public Post() 
        this.createTime = new java.util.Date();
    

    public Post(String comment, int likes, int dislike, User user_id_fk) 
        this.user_id_fk = user_id_fk;
        this.comment = comment;
        this.likes = likes;
        this.dislike = dislike;
        this.createTime = new java.util.Date();
    

    public Post(int id, User user_id_fk, String comment, int likes, int dislike) 
        this.id = id;
        this.user_id_fk = user_id_fk;
        this.comment = comment;
        this.likes = likes;
        this.dislike = dislike;
        this.createTime = new java.util.Date();
    

加上Getters & Setters & toString()。

发布请求(我正在使用 Postman 发送请求):


"comment" : "This is a comment",
"likes" : 123,
"dislike" : 1,
"user_id_fk" :
[
    
        "id" : 1
    
]

在 "user_id_fk" 的请求中,我尝试使用 [ "id" : 1 ] 和 "id" : 1 但结果是一样的。

问题:

当我从我的控制器执行完全相同的代码时,一切正常的情况除外。请记住,我正在使用依赖项“spring-boot-starter-data-rest”。 此外,当我在没有“optional = false”“nullable = false” 的情况下执行代码时,会将数据插入数据库但“user_id_fk”为空:(。

我得到的错误:

not-null property references a null or transient value : com.citizen.citizen.entity.Post.user_id_fk; 
nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.citizen.citizen.entity.Post.user_id_fk]

这意味着外键("user_id_fk") 为空但不应为空。 任何帮助将不胜感激。

【问题讨论】:

您为什么将您的用户命名为 user_id_fk?它被标识为连接列名称,但为什么还要将引用的实体命名为呢?我之前曾让 spring 对这样的命名冲突感到困惑。 我尝试使用另一个名称,例如“用户”,但我仍然遇到同样的问题。 id 为 1 的用户是否已经存在,或者您是否也在尝试创建它? 是的,ID 为 1 的用户存在。实际上我在数据库中有几个用户。我还尝试发送 ID 为 1 的用户的所有信息,但我又遇到了同样的错误。 【参考方案1】:

我只是删除了依赖项“spring-boot-starter-data-rest”,然后通过创建自定义休息解决了这个问题,一切正常。亲吻!

【讨论】:

我也遇到了同样的问题,你是怎么做到的?【参考方案2】:

根据this 文章,您应该使user_id_fk 可以为空,然后:

    发送 POST 创建用户 发送第二个 POST 以创建帖子 发送 PUT 以创建两者之间的关系。

This 文章声明相同。 而documentation 只提到通过关联链接处理关联。

【讨论】:

感谢您的回复。我明白你在说什么,但发送第二个请求也不适合我的用例。如果可能的话,我想在一个 POST 请求中进行。 我添加了更多链接,但是根据我对 Spring Data REST 的了解,您想要的是不可能的。您需要为此编写自定义控制器。 每个 cmets,用户已经存在,所以这应该可以通过单个查询来实现。 即使用户存在,您仍然需要两个查询:一个用于创建帖子,另一个用于将帖子分配给用户。除非我误解了什么? 是的,因为我可以理解您是正确的文档。无论如何,这种解决方法对我不起作用,我在不使用依赖项“spring-boot-starter-data-rest”的情况下完成了所有 REST 自定义。

以上是关于空外键(Springboot、Hibernate、Postman)的主要内容,如果未能解决你的问题,请参考以下文章

为可空外键创建导航属性

无法插入具有空外键的实体

如何在 BackAnd 中过滤空外键或对象关系的集合?

SQL - 空外键或联结表?

数据库建模:按实体类型的空外键

Hibernate:如何将自动生成的外键列名从小写更改为大写