【问题标题】:Saving entity with existing children with CRUD Repository fails because of duplicate key由于重复键,使用 CRUD 存储库保存具有现有子级的实体失败
【发布时间】:2015-12-15 20:50:51
【问题描述】:

一个User 可以有多个Authorities。默认情况下,当我创建一个新用户时,我想给他添加ROLE_USER 权限。

这是用户实体:

@Entity
@Table(name = "Users")
public class User
{
    @Id    
    private String username;
    private String password;
    private String email;
    @OneToMany
    @JoinTable(
      name = "UserAuthority",
      joinColumns = @JoinColumn(name = "username"),
      inverseJoinColumns = @JoinColumn(name = "authority"))
    private List<Authority> authorities = new ArrayList<>();

和权威实体:

@Entity
public class Authority
{
    @Id
    private String authority;

我使用基本的UserRepositoryAuthorityReposiroty 都扩展CrudRepository

这是注册新用户的方法:

public String register(User user)
{
    if (userRepository.findOne(user.getUsername()) != null)
    {
        return "User with given username already exists!";
    }
    user.setPassword(passwordEncoder.encode(user.getPassword()));
    user.getAuthorities().add(authRepository.findOne("ROLE_USER"));
    userRepository.save(user);
    return "User successfully registered!";
}

当我尝试注册新用户时失败并出现以下错误:

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_c1gaghspdr9qx2yt45moye10y"
  Detail: Key (authority)=(ROLE_USER) already exists.

我可以在日志中看到 Hibernate 正在尝试插入 ROLE_USER 权限,这是不可能的,因为它已经存在,但我不明白为什么。我还没有在@OneToManyannotation 上设置级联属性。

如何实现我想要的?

这是我的配置:

compile('org.springframework.boot:spring-boot-starter-data-jpa')
runtime('org.postgresql:postgresql:9.4-1206-jdbc42')

提前致谢!

【问题讨论】:

  • 您的用户似乎已经拥有权限。您使用列表而不是集合隐式处理唯一性的任何原因?
  • 我刚刚尝试了 Set 并且错误保持不变。问题是 Hibernate 试图插入 ROLE_USER 权限。我可以在日志中看到这一点:休眠:插入用户(电子邮件,密码,用户名)值(?,?,?)休眠:插入用户授权(用户名,权限)值(?,?)
  • 我刚刚在 pgAdmin 中发现我要创建的表(UserAuthority)被命名为“user_authority”并且它具有约束“UNIQUE(authority)”?!

标签: spring hibernate spring-boot spring-data-jpa one-to-many


【解决方案1】:

问题在于关系。您拥有 OneToMany - 意味着在其他站点上是关系 ManyToOne... 如果您在一个用户中使用了某些权限,则不能将此实体(对象)用于其他用户。

您的问题的解决方案是在 User 类中更改与 @ManyToMany insted @OneToMany 的关系。强度不大,但实际上是ManyToMany关系,因为User可以有很多权限,任何一个thority都可以在很多用户中使用。

【讨论】:

  • 谢谢,成功了!只有一个与命名相关的问题:为什么我的表名为“user_authority”,即使我在@JoinTable 将其名称设置为“UserAuthority”?
  • 这取决于数据库方言。 Hibernate 更改表名并使用“_”而不是 CamelCase 拆分单词。您可以尝试通过创建具有多个单词名称的其他实体。例如,在 Oracle 中,您的表名都带有“userauthority”之类的小写字母
  • @matiska 具体来说,看看 Hibernate 命名策略。
猜你喜欢
  • 1970-01-01
  • 2021-05-14
  • 2022-09-28
  • 1970-01-01
  • 2022-01-24
  • 2020-09-12
  • 2012-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多