从系统中删除用户时遇到问题。变化的关键约束

Posted

技术标签:

【中文标题】从系统中删除用户时遇到问题。变化的关键约束【英文标题】:Having trouble deleting user from system. Volating key constraints 【发布时间】:2021-07-18 19:31:14 【问题描述】:

每当我尝试从我的应用程序中删除用户时都会收到错误消息。

我的控制器方法

@RequestMapping(value = "/delete/id", method = RequestMethod.GET)
@ResponseBody
public String deleteStudent(@PathVariable(name = "id") Long id) 
    userService.delete(id);
    return "users";

我的users.html

<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <title>Users</title>
    <style>
        /*body,html height:100%;overflow:hidden;*/
        body 
            margin: 0;
            width: 100%;
            height: 100%;
            position: absolute;
        

        .hero 
            position: relative;
            height: 100vh;
            width: 100%;
            display: flex;
            /*align-items: center;*/
            /*justify-content: center;*/
        

        .hero::before 
            content: "";
            background-image: url(https://wallpaperaccess.com/full/3138960.jpg);
            background-size: cover;
            position: absolute;
            top: 0px;
            right: 0px;
            bottom: 0px;
            left: 0px;
            opacity: 0.5;
        

        .content 
            position: relative;

        

        .topnav 
            overflow: hidden;
            background-color: #333;
        

        .topnav a 
            float: left;
            display: block;
            color: #f2f2f2;
            text-align: center;
            padding: 14px 16px;
            text-decoration: none;
            font-size: 17px;
        

        .topnav a:hover 
            background-color: #ddd;
            color: black;
        

        .topnav a.active 
            background-color: #4CAF50;
            color: white;
        

        .topnav .icon 
            display: none;
        

        @media screen and (max-width: 600px) 
            .topnav a:not(:first-child) display: none;
            .topnav a.icon 
                float: right;
                display: block;
            
        

        @media screen and (max-width: 600px) 
            .topnav.responsive position: relative;
            .topnav.responsive .icon 
                position: absolute;
                right: 0;
                top: 0;
            
            .topnav.responsive a 
                float: none;
                display: block;
                text-align: left;
            
        
        table 
            border-collapse: separate;
        

        th 
            background-color: #4287f5;
            color: white;
        

        th,
        td 
            width: 150px;
            text-align: center;
            border: 1px solid black;
            padding: 5px;
        
    </style>
</head>
<body>

<div class="topnav" id="myTopnav">
    <a th:href="@/admin/adminIndex" class="active">Home</a>
    <a th:href="@/admin/users">Users</a>
    <a th:href="@/perform_logout" >Logout</a>
    <a href="javascript:void(0);" class="icon" onclick="myFunction()">
        <i class="fa fa-bars"></i>
    </a>
</div>

<div class="hero">
    <div class="content">
        <div>
            <h1>Welcome to the users section</h1>
            <h2>List of users:</h2>

            <table>
                <tr>
                    <th>Id</th>
                    <th>Name</th>
                    <th>Username</th>
                    <th>Email</th>
                    <th>Role</th>
                    <th>Confirmed</th>
                    <th>Option</th>
                </tr>

                <tr th:each="User : $userList">
                    <td th:text="$User.id">Id</td>
                    <td th:text="$User.name">Name</td>
                    <td th:text="$User.username">Username</td>
                    <td th:text="$User.email">Email</td>
                    <td th:text="$User.roles">Role</td>
                    <td th:text="$User.confirmed">Confirmed</td>
                    <td>
<!--                        <a th:href="|@/delete/$User.id|" onclick="return confirm('Are you sure?')">Delete</a>-->
                        <a th:href="@delete/__$User.id__" class="btn btn-danger">Delete</a>
                    </td>
                </tr>
            </table>
        </div>
    </div>
</div>

<script>
    function myFunction() 
        var x = document.getElementById("myTopnav");
        if (x.className === "topnav") 
            x.className += " responsive";
         else 
            x.className = "topnav";
        
    
</script>

<script type="text/javascript">
    $(function()
        var $page = jQuery.url.attr("file");
        $('ul.navigation li a').each(function()
            var $href = $(this).attr('href');
            if ( ($href == $page) || ($href == '') ) 
                $(this).addClass('on');
             else 
                $(this).removeClass('on');
            
        );
    );
</script>

</body>
</html>

我的User.java

package com.lukas.ramonas.cms.Model;

import com.lukas.ramonas.cms.Validators.ValidEmail;

import javax.persistence.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/*******************************************
 * Defined user model
 *******************************************/
@Entity
@Table(name = "user_table", schema = "public")
public class User 

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

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

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

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

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

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

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(
            name = "user_role_table",
            joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"))
    private Collection<Role> roles = new HashSet<>();



/*******************************************
* Setters and getters
*******************************************/

    public Long getId() 
        return user_id;
    

    public void setName(String name) 
        this.name = name;
    

    public String getName() 
        return name;
    

    public void setUsername(String username) 
        this.username = username;
    

    public String getUsername() 
        return username;
    

    public void setPassword(String password) 
        this.password = password;
    

    public String getPassword() 
        return password;
    

    public void setEmail(String email) 
        this.email = email;
    

    public String getEmail() 
        return email;
    

    public void setConfirmed(Boolean confirmed) 
        this.confirmed = confirmed;
    

    public Boolean getConfirmed() 
        return confirmed;
    

    public void setRoles(Collection roles) 
        this.roles = roles;
    

    public Collection<Role> getRoles()  return this.roles;
    

错误

org.postgresql.util.PSQLException: ERROR: update or delete on table "privilege_table" violates foreign key constraint "role_privilege_table_privilege_id_fkey" on table "role_privilege_table"
  Detail: Key (privilege_id)=(1) is still referenced from table "role_privilege_table".

    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2532) ~[postgresql-42.2.14.jar:42.2.14]
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2267) ~[postgresql-42.2.14.jar:42.2.14]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:312) ~[postgresql-42.2.14.jar:42.2.14]
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:448) ~[postgresql-42.2.14.jar:42.2.14]
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:369) ~[postgresql-42.2.14.jar:42.2.14]
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:153) ~[postgresql-42.2.14.jar:42.2.14]
    ...

从错误中,我假设每当我删除用户时,权限表实例也因某种原因试图被删除。我在网上查看是否有其他人有同样的问题,我发现 this thread 并没有给我带来任何好的结果。

非常感谢任何提示或帮助!

【问题讨论】:

【参考方案1】:
 @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(
            name = "user_role_table",
            joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"))
    private Collection<Role> roles = new HashSet<>();

在这里你使用@ManyToMany。这意味着一个用户可以拥有多个角色,但一个角色也属于多个用户。

由于其他用户也可以与同一角色建立关系,因此您不能在该关系上拥有CascadeType.ALL。 All 还包含级联删除,这将导致删除用户休眠的操作也会尝试删除角色。但其他用户可能已经拥有该角色。因此,您收到的异常。

你可以试试

 @ManyToMany(cascade = CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH , fetch = FetchType.EAGER)
   @JoinTable(
                name = "user_role_table",
                joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "user_id"),
                inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "role_id"))
        private Collection<Role> roles = new HashSet<>();

最接近您使用的那个 (CascadeType.ALL) 但没有删除。

【讨论】:

感谢您的回复!我认为这可能有效,尽管现在每当我尝试登录系统ERROR: relation "user_table_roles" does not exist 时都会遇到不同的错误。这很奇怪,因为我没有使用该名称指定的表,只有表 user_role_table。我不知道它为什么这样做 我通过删除我在测试时放置的@CollectionTable 来修复ERROR: relation "user_table_roles" does not exist。我用你的方法级联,是的,这解决了我的问题。再次感谢您,我将您的回复标记为答案

以上是关于从系统中删除用户时遇到问题。变化的关键约束的主要内容,如果未能解决你的问题,请参考以下文章

作为系统用户,我遇到此错误:ORA-01031:权限不足

sqlserver 删除索引时遇到的问题,请高手指教!!!

删除元素时使用 JoinTable 和 OrderColumn 的 Hibernate 单向 OneToMany 映射中的约束冲突

如何在 SQLAlchemy 中删除外键约束?

从封装变化的角度看设计模式——对象创建

从封装变化的角度看设计模式——对象创建