【问题标题】:Postgresql throw null value in column violates not-null constraint when using oneToMany relationship in JPA在 JPA 中使用 oneToMany 关系时,Postgresql 在列中抛出空值违反了非空约束
【发布时间】:2017-07-08 18:04:20
【问题描述】:

我尝试测试 Hibernate 的一对多关系。我将 Post 和 PostComment 实体定义如下: Post.java

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

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

    @Id
    @Column(name="post_id")
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Long postId;

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

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "post",
            orphanRemoval = true)
    private List<PostComment> comments = new ArrayList<>();

    public Post() {};

    public Post(String title) {
        this.title = title;
    }
   // Add getter and setter
}

PostComment.java

    import javax.persistence.*;

@Entity
@Table(name = "post_comment")
public class PostComment {
    @Id
    @Column(name="comment_id")
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Long commentId;

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "post_id")
    private Post post;

    public PostComment() {};
    public PostComment(String review) {
        this.review = review;
    }
    // Add getter and setter
}

PostRepository.java

public interface PostRepository extends JpaRepository<Post,Long> {
}

db-changelog.xml

<changeSet id="1" author="dev">
    <createTable tableName="post_comment">
        <column name="comment_id" type = "bigint">
            <constraints nullable="false" primaryKey="true"></constraints>
        </column>
        <column name="review" type="varchar(255)"></column>
    </createTable>
    <createTable tableName="post">
        <column name="post_id" type="bigint">
            <constraints nullable="false" primaryKey="true"></constraints>
        </column>
        <column name="title" type = "varchar(255)"></column>
    </createTable>
</changeSet>

然后,我使用 SpringJUnit 在 PostServiceITTest.java 中添加新帖子

 import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import java.util.Arrays;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebAppConfiguration
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@ActiveProfiles("devmock")
public class PostServiceITTest {
    @Autowired
    private PostRepository postRepository;

    @Test
    public void testAddPost(){
        Post post = new Post(" Post 1");

        PostComment postComment1 = new PostComment(" Post comment 1");  
        PostComment postComment2 = new PostComment(" Post comment 2");
        post.setComments(Arrays.asList(postComment1,postComment2));

        postRepository.save(post);
    }
}

不幸的是,测试抛出了一个与 null-violate 约束相关的 Postgresql 错误:

    Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "post_id" violates not-null constraint
  Detail: Failing row contains (null,  Post 1).

非常感谢您的宝贵时间。

【问题讨论】:

  • 您没有为post_id 传递值。
  • 你能确认数据库表有你期望的列名吗?
  • 我也遇到了同样的问题。一年半后有什么解决办法吗?

标签: java postgresql hibernate jpa


【解决方案1】:

您似乎没有传递post_id 的值。

【讨论】:

  • 感谢您的回答。但是,我将 post_id 设置为 auto @GeneratedValue。我想我不需要为 post_id 增加价值。此外,我尝试添加“ post.setPostId(1L);”在“发布帖子 = 新帖子(“帖子 1”)之后;“并再次运行它。新异常抛出“原因:org.postgresql.util.PSQLException:错误:列 cmets1_.post_id 不存在位置:335”
  • 您可以在设置 cmets 之前先保存 Post 对象吗?
  • 是的,我尝试先保存,然后更新 PostComment 但同样的异常 'column cmets1_.post_id 不存在'
【解决方案2】:

在您的PostComment 类中,您有一个字段private Post post。我怀疑你是否设置了那个字段。

一种选择是将Post post 作为构造函数参数添加到PostComment 类(连同默认构造函数),并将其与Post 对象一起实例化,如下所示:

public PostComment(String review, Post post) {
  this.review = review;
  this.post = post;
}

在构造对象时使用:

PostComment postComment1 = new PostComment(" Post comment 1", post);

而不是

PostComment postComment1 = new PostComment(" Post comment 1");

或者另一种方法是在 Post 类中添加脚手架代码,例如:

public void addPostComment(PostComment comment) {
    comments.add(comment);
    comment.setPost(this);
}

并在将PostComment 更新/添加到Post 类中的列表时使用此方法。

【讨论】:

  • 感谢您的解决方案。我这样做的例外是“post_id”列中的空值违反了非空约束。我正在考虑我的 liquibase。
【解决方案3】:

我已通过删除现有数据库并使用spring.jpa.hibernate.ddl-auto=create-drop 生成新数据库来解决此问题。当然,只有在数据库中没有有价值的数据时才能这样做。完成后,改回spring.jpa.hibernate.ddl-auto=update

【讨论】:

  • 这不应该被否决,它肯定有助于将新生成的表与您手动创建的表进行比较。
【解决方案4】:

以下代码可能有效;您也可以在 child 中设置父引用...

{       Post post = new Post(" Post 1");

        PostComment postComment1 = new PostComment(" Post comment 1");  
        postComment1.setPost(post); // < -- here
        PostComment postComment2 = new PostComment(" Post comment 2");
        postComment2.setPost(post); // < -- here

        post.setComments(Arrays.asList(postComment1,postComment2));

        postRepository.save(post); 
}

如果您使用lombok生成toString()方法,请排除postComment.post以避免无限循环(导致stak溢出);

@ToString(exclude = { "post" })
public class PostComment{
// ...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-11-25
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    相关资源
    最近更新 更多