简体   繁体   English

Spring数据JPA延迟加载

[英]Spring data JPA lazy loading

I'm very new to Java Spring and I'm trying for a few days to get my relationship working, but it doesn't.我对 Java Spring 很陌生,我尝试了几天来让我的关系正常工作,但事实并非如此。 I'm using Java Spring and Mysql.我正在使用 Java Spring 和 Mysql。

The Admin should add Employees to the database.管理员应该将员工添加到数据库中。 The Employees will only see specific data.员工只会看到特定的数据。 My problem is, that I don't understand how I can make a right POST request from the EmployeesController and get the user_id from the User Model.我的问题是,我不明白如何从 EmployeesController 发出正确的 POST 请求并从用户模型中获取 user_id。 I tried some different implementations, but I still cannot get it to work.我尝试了一些不同的实现,但我仍然无法让它工作。

I have an entity for Users, Roles and Employees.我有一个用于用户、角色和员工的实体。 An employee is always a user, but a user may not be an employee.员工始终是用户,但用户可能不是员工。 So my database structure is as follows:所以我的数据库结构如下:

users:用户:

+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(30)  | NO   |     | NULL    |                |
| email    | varchar(100) | NO   |     | NULL    |                |
| password | varchar(100) | NO   |     | NULL    |              
+----------+--------------+------+-----+---------+----------------+

employees:雇员:

+-------------------+--------------+------+-----+---------+----------------+
| Field             | Type         | Null | Key | Default | Extra          |
+-------------------+--------------+------+-----+---------+----------------+
| id                | int          | NO   | PRI | NULL    | auto_increment |
| academic_title    | varchar(100) | NO   |     | NULL    |                |
| department        | varchar(100) | NO   |     | NULL    |                |
| user_id           | int          | NO   |     | NULL    |                |
+-------------------+--------------+------+-----+---------+----------------+

Only an admin can add an employee to the system, the employees can only log in and see some data.只有管​​理员可以向系统添加员工,员工只能登录并查看一些数据。 So like I understand in Java Spring parameters like user_id in employees table are not extra written in the model.所以就像我在 Java Spring 中理解的,员工表中的 user_id 等参数并没有额外写入模型中。 So this is what I have right now:所以这就是我现在所拥有的:

Employee.java雇员.java

@Entity
@Table(name = "employees")
public class Employee{
  
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Size(min=3, max = 100)
    private String academic_title;

    @Size(min=3, max = 100)
    private String department;

    public Employee() {}
 
    public Employee(String academic_title, String department) {
        super();
        this.academic_title = academic_title;
        this.department = department;
    }
    
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }

    public String getDepartment() {
        return department;
    }
 
    public void setDepartment(String department) {
        this.department = department;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

User.java用户.java

@Entity
@Table(name = "users")
public class User{
  @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
  
    @NotBlank
    @Size(min=3, max = 50)
    private String username;
 
    @NaturalId
    @NotBlank
    @Size(max = 50)
    @Email
    private String email;
 
    @NotBlank
    @Size(min=6, max = 100)
    private String password;
 
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_roles", 
      joinColumns = @JoinColumn(name = "user_id"), 
      inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();

    @OneToOne(fetch = FetchType.LAZY,
            cascade =  CascadeType.ALL,
            mappedBy = "user")
    private Employee employee;
 
    public User() {}
 
    public User(String username, String email, String password) {
        super();
        this.username = username;
        this.email = email;
        this.password = password;
    }
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public Set<Role> getRoles() {
        return roles;
    }
 
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}

EmployeeController.java (create Employee function) EmployeeController.java(创建Employee函数)

    public Employee createEmployee(@PathVariable (value = "user_id") Long user_id,
                                 @Valid @RequestBody Employee employee) {
                                     
        userRepository.findById(user_id);
        employeeRepository.save(employee);
        return employee;

    }

userRepository.java用户存储库.java

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
    Optional<User> findById(Long id);
    Boolean existsByUsername(String username);
    Boolean existsByEmail(String email);
}

My Postman POST request to add employees:我的邮递员 POST 请求添加员工:

{
    "academic_title": "xy",
    "department": "xx",
    "user_id": 5
}

When I try to save the user_id as a normal Long parameter, I can save it to the database.当我尝试将 user_id 保存为普通 Long 参数时,我可以将其保存到数据库中。 But then when I fetch the existing employees, the join function doesn't work so I cannot see who user_id 5 is.但是当我获取现有员工时,join 函数不起作用,所以我看不到 user_id 5 是谁。 And when I try it the other way, like the code above I'm getting an error like: not-null property references a null or transient value or something like Employee column: user_id (should be mapped with insert="false" update="false") .当我以另一种方式尝试时,就像上面的代码一样,我收到了一个错误,例如: not-null 属性引用了一个空值或瞬态值或类似Employee 列的内容:user_id(应该映射为 insert="false" update= “假”) So I don't know what to do, I'm stuck in this problem for 5 days.所以我不知道该怎么办,我被这个问题困了 5 天。

Thanks in advance for your help!在此先感谢您的帮助!

If you decided to define your relationship using Hibernate and annotation @OneToOne , you should keep in your mind now Employee has a class property (attribute) User.如果你决定使用 Hibernate 和注解@OneToOne来定义你的关系,你应该记住现在 Employee 有一个类属性(属性)User。 And for store foreign key from the employee table on the user table you need to set User instance to Employee.并且要从用户表上的员工表中存储外键,您需要将用户实例设置为员工。

You should try something like this in your case:你应该在你的情况下尝试这样的事情:

public Employee createEmployee(@PathVariable (value = "user_id") Long user_id,
                             @Valid @RequestBody Employee employee) {
                                 
    // find user by id or else throw exception
    User userById = userRepository.findById(user_id).orElseThrow(() -> new 
    RuntimeException("Not found."));
    
    // set user into employee. it's like binding two entities
    employee.setUser(userById);

    // after that you can save your employee entity.
    return employeeRepository.save(employee);
    
}

the join function doesn't work加入功能不起作用

the fetch type between User and Employee is Lazy. User 和 Employee 之间的 fetch 类型是 Lazy。 which means that it does not actually load the user when loading an employee.这意味着它在加载员工时实际上并没有加载用户。 Instead, it loads them when requested to do so.相反,它会在请求时加载它们。

So as @Zooger mentioned, you should load the user from database first.正如@Zooger 提到的,您应该首先从数据库加载用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM