【问题标题】:Updating the instance of super class to an instance of sub class when using the single table strategy in hibernatehibernate中使用单表策略时将超类的实例更新为子类的实例
【发布时间】:2019-05-13 09:45:47
【问题描述】:

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

我已经使用 java 类创建了实体并映射了每个实体。 我没有在以下代码中提供 Project 和 Tasks 类。如有需要我可以提供。

下面是 User 类。

@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

下面是继承的Employee类

@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 的实例向下转换为 Employee 的实例,这会导致 CastException。

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

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

以下是 er 模型的草图

【问题讨论】:

  • 不能。 Java 对象有一个类型,Java 对象的类型是不能改变的。您需要不使用 JPA,而是使用 JDBC 来修改表中的 DTYPE 列,或者(更好)您需要更改设计并使用组合而不是继承:使用 具有 角色,并且此角色可以是员工或经理。
  • 哦,好的。因此,如果我使用组合而不是继承,我是否能够将用户从用户类型更改为员工类型或经理类型,并在特定项目完成后再次返回用户。你能推荐一个学习作文的教程吗?谢谢顺便说一句。
  • 是的:user.setRole(managerRole); user.setRole(basicUserRole);
  • 我已经上传了答案,它工作正常@JBNizet

标签: mysql hibernate spring-boot spring-data-jpa single-table-inheritance


【解决方案1】:

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

员工类如下

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

而Managers类如下

@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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-29
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 2011-04-18
    • 1970-01-01
    相关资源
    最近更新 更多