在休眠中使用单个 table 策略时,将 super class 的实例更新为 sub class 的实例

Updating the instance of super class to an instance of sub class when using the single table strategy in hibernate

我正在开发一个项目管理系统,该系统具有三个用户,即员工、经理和 HRM。员工和经理在具有多对多递归关系的同一实体中(我们称此为员工实体)。 Employee 实体和 HRM 实体继承了 User 实体。这里使用的hibernate继承策略是single-table。 最初,当用户注册时,他被保存为用户的实例(用户类型的存储库)。当他被分配到特定项目时,我想将用户实例更新为员工实例或经理实例。如何使用 spring 数据 jpa 来实现。我正在使用 spring boot.

做这个项目

我使用 java classes 创建了实体并映射了每个实体。 我没有在以下代码中提供项目和任务 class。如果需要我可以提供。

以下是用户class。

@Entity
@Table(name = "users")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
        name="User_Type",
        discriminatorType=DiscriminatorType.STRING
        )
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="user_id")
    private Long id;

    private String name;

    private String email;

    private String password;

    private String mobilenumber;

    private String gender;

    private String resetToken;

    @ManyToMany(fetch = FetchType.LAZY, cascade={CascadeType.ALL})
    @JoinTable(name = "user_roles", 
        joinColumns = @JoinColumn(name = "user_id"), 
        inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();//roles refer to the employee,manager and HRM roles

//public getters and setters

以下是继承的Employeeclass

@Entity
@DiscriminatorValue("Employee")
public class Employee extends User {
    @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
    @JoinTable(name = "employee_project",
    joinColumns = @JoinColumn(name = "user_id"),
    inverseJoinColumns = @JoinColumn(name = "project_id")
    )
    private Set<Project> project = new HashSet<>();

    @ManyToMany
    @JoinTable(name = "employee_tasks",
    joinColumns = @JoinColumn(name = "user_id"),
    inverseJoinColumns = @JoinColumn(name = "task_id")
    )
    private Set<Task> tasks = new HashSet<>();

    @ManyToMany
    @JoinTable(name = "rm_employee",
    joinColumns = @JoinColumn(name = "user_id"),
    inverseJoinColumns = @JoinColumn(name = "rm_id")
    )
    private Set<Employee> managers = new HashSet<>();

    @ManyToMany
    @JoinTable(name = "rm_employee",
    joinColumns = @JoinColumn(name = "rm_id"),
    inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    private Set<Employee> employees = new HashSet<>();

//public getters and setters

我尝试了以下将 User 实例向下转换为导致 CastException 的 Employee 实例的方法。

Optional<User> optional = userRepo.findById(id);

Employee employee = (Employee)optional.get();

以下是er模型的草图

我能够在不使用继承的情况下解决问题。实际上我不得不避免继承,因为 java 担心类型不能从一个更改为另一个。在此示例中,类型 User 无法按您的意愿转换为 Employee 或 Manager。所以解决方案是为经理和员工创建两个单独的 classes(这不应该像我在问题中所做的那样扩展用户 class)。这两个应该被注释为 Entity 并且应该有一个 Id 字段。您可以在 classes 中拥有一个带有上述 Id 字段的构造函数,并且当您将用户分配给项目时,您可以使用此构造函数,具体取决于他是经理还是员工来创建相应的经理实例或员工。

员工class如下

public class Employee{

    @Id
    private Long employeeId;

    @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
    @JoinTable(name = "employee_project",
    joinColumns = @JoinColumn(name = "employee_id"),
    inverseJoinColumns = @JoinColumn(name = "project_id")
    )
    private Set<Project> project = new HashSet<>();

    @ManyToMany
    @JoinTable(name = "employee_rm",
    joinColumns = @JoinColumn(name = "employee_id"),
    inverseJoinColumns = @JoinColumn(name = "rm_id")
    )
    private Set<Manager> managers = new HashSet<>();

    @ManyToMany
    @JoinTable(name = "employee_tasks",
    joinColumns = @JoinColumn(name = "employee_id"),
    inverseJoinColumns = @JoinColumn(name = "task_id")
    )
    private Set<Task> tasks = new HashSet<>();

    public Employee() {}

    public Employee(Set<Project> project, Set<Manager> managers, Set<Task> tasks, Long employeeId ) {
        super();
        this.project = project;
        this.managers = managers;
        this.tasks = tasks;
        this.employeeId=employeeId;
    }
//with public getters and setters

和经理class如下

@Entity
public class Manager {

    @Id
    private Long managerId ;

    @ManyToMany
    @JoinTable(name = "manager_employee",
    joinColumns = @JoinColumn(name = "manager_id"),
    inverseJoinColumns = @JoinColumn(name = "user_id")
    )
    private Set<Employee> employees = new HashSet<>();

    @OneToOne
    @JoinColumn(name="project_id")
    private Project project;

    public Manager() {}

    public Manager(Long managerId) {
        super();
        this.managerId = managerId;
    }
//public getters and setters