当前位置: 首页 > 知识库问答 >
问题:

ManyToOne双向关系中POST请求的org.hibernate.exception.ConstraintViolationException

东门茂实
2023-03-14

我正在尝试在 /addNewUser 终结点上使用以下 POST 请求创建新用户:-

发布请求

{
    "username"   : "abc",
    "password"   : "123",
    "enabled"    : "true",
    "authorities": [{ 
                        "authority" : "ROLE_USER" 
                    }]
}

UserController类:-

@PostMapping("/addNewUser")
    public UserModel addNewUser(@RequestBody UserModel user) {
        return userService.addNewUser(user);
    }

用户服务类:-

public UserModel addNewUser(UserModel user) {
        return userRepository.saveAndFlush(user);
    }

用户存储库界面

public interface UserRepository extends JpaRepository<UserModel, String> {

}

但我得到了以下例外:-

2020-04-30 21:14:00.441 ERROR 23653 --- [nio-8080-exec-7] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: null value in column "authority" violates not-null constraint
  Detail: Failing row contains (null, null).
2020-04-30 21:14:00.450 ERROR 23653 --- [nio-8080-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [authority]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause

org.postgresql.util.PSQLException: ERROR: null value in column "authority" violates not-null constraint
  Detail: Failing row contains (null, null).

用户模型类

@Entity
@Table(name = "users")
public class UserModel {
    @Id
    @Column(name = "username", unique = true, nullable = false)
    private String username;

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

    @Column(name = "enabled")
    private boolean enabled;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    @JsonManagedReference
    private List<AuthoritiesModel> authorities;

    //getters and setters
}

AuthoritiesModel类:-

@Entity
@Table(name = "authorities")
public class AuthoritiesModel implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @JsonBackReference
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name="username", unique = false, nullable=false)
    private UserModel user;

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

    //getters and setters
}

最初,我认为我的post请求或Jackson API的反序列化存在一些问题,所以我打印了控制器方法中UserModel字段的值,并且所有值都设置正确,包括AuthoritiesModel。但是当我尝试持久化UserModel对象时,它会引发异常。

更新1:

如果我在没有权限的情况下发布请求,它不会引发任何异常,但我在响应中将权限设置为 null。

发布请求

{
    "username"   : "abc",
    "password"   : "123",
    "enabled"    : "true"
}

回复后

{
    "username": "abc",
    "password": "123",
    "enabled": true,
    "authorities": null
}

共有2个答案

宗项禹
2023-03-14

在我开始回答之前,让我澄清一下我没有的那个明显的问题

首先,我认为hibernate用代理封装代码,Jackson绑定代码也使用反射,而不是调用传统的getter和setter。此外,Hibernate本质上使用标志来确定对象是否被触摸,通过查看通过getter和setter调用了哪些方法,一对多映射的字段看起来不是,因为它们是通过反射设置的。所以我试着推出一些简单的系统。在setter中的println看到他们实际上正在被调用。所以这不是我的问题。

其次,我使用了单元测试,没有做POST请求,而是直接调用服务层中的方法,看看是否发生了对数据库的写入。但是没有。

所以,答案是显而易见的: -

服务层应调用两个存储库层对象。服务层对象应该是一对多存储库对象。这是标准做法,在跨 Web 服务实现时也经常使用。

但是我不明白为什么我们需要添加一个单独的调用来添加已经在我们的实体和它们的映射中定义的东西。我不确定我是否做错了或者理解错了,但是我觉得hibernate应该足够聪明来处理这种情况。理想情况下,它应该首先持久化父对象,然后使用我们的映射从数据库获取详细信息,并根据它持久化子对象。但这里的问题是,您要求它知道对象中的活动不在数据库中,应该创建并绑定到该用户模型,似乎级联应该这样做,但它不会。

翟鹏
2023-03-14

当请求正文反序列化时,AuthoritiesModel没有设置UserModel

您可以尝试以下操作:

public UserModel addNewUser(UserModel user) {
    List<AuthorityModel> authorities = user.getAuthorities();
    authorities.stream().forEach(authority -> authority.setUser(user);
    return userRepository.saveAndFlush(user);
}
 类似资料:
  • 我在将带有@ManyToOne关系的实体(雇员)映射到带有@OneToMany关系的实体(社区)时遇到了问题。 当我将一个实体(社区)分配给一个实体(员工),其中社区的值为空时,它工作正常。 问题出现了,如果雇员已经为社区分配了价值。当我更改该值并保存更改时,该员工为社区获得了新的值,并且这个新社区在集合中获得了该员工。唯一的问题是,老社区仍然有这个员工在收集,但它应该被删除。这只有在数据库重新启

  • 我试图在用户和地址之间建立双向关系, 用户1-------->*地址 但是 地址1-------->1个用户 我在上网时得到了这些信息 > 对于一对一双向关系,拥有方对应于包含对应外键的方 双向关系的反向侧必须通过使用OneToOne、 OneToMany或ManyToMany批注的mappedBy元素来引用其 所属侧。mappedBy元素指定作为 关系所有者的实体中的属性或字段。 但如果我按照情

  • 服务 我的主要方法 所以在这里,当我尝试在students表中添加学生时,它给出了一个错误,错误是Falling

  • 问题内容: 假设我有两个实体: 然后,我要保留“客户”实体,然后,参照先前添加的“客户”保留“订单”实体。当我从数据库中检索此客户并调用getOrders时,它将返回空集。这是正常行为吗?如果是,当我添加新的Order实体时,我该怎么做以自动刷新此集合? 问题答案: Jpa不会为您维护关系,因此应用程序需要设置双向关系的两端,以使它们与数据库保持同步。当您设置了order-> customer关系

  • 问题内容: 在JPA注释参考的示例部分中: 示例1-59 @OneToMany-具有泛型的客户类 示例1-60 @ManyToOne-具有泛型的Order类 在我看来,实体是协会的所有者。但是,在同一文档中对属性的说明中写道: 如果关系是双向的,则将关联的反(非所有权)侧的maptedBy元素设置为拥有该关系的字段或属性的名称,如示例1-60所示。 但是,如果我没有记错,则在示例中看起来,实际上是

  • 我有2个JParepository: 为了保存一份有几个参与者的新合同,我正在邮递员中执行以下步骤: 创建契约并获取其href: 没运气。出于某种原因,系统将该字段留空,而不是使用步骤1中创建的实体的foreing键。我做错了什么?