Spring 数据 JPA 延迟加载
Spring data JPA lazy loading
我是 Java Spring 的新手,我尝试了几天让我的关系正常运转,但没有成功。我正在使用 Java Spring 和 Mysql.
管理员应将员工添加到数据库中。员工将只能看到特定数据。我的问题是,我不明白如何从 EmployeesController 发出正确的 POST 请求并从用户模型中获取 user_id。我尝试了一些不同的实现,但仍然无法正常工作。
我有一个用户、角色和员工实体。员工始终是用户,但用户可能不是员工。所以我的数据库结构如下:
用户:
+----------+--------------+------+-----+---------+----------------+
| 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 |
+----------+--------------+------+-----+---------+----------------+
员工:
+-------------------+--------------+------+-----+---------+----------------+
| 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 | |
+-------------------+--------------+------+-----+---------+----------------+
只有管理员才能将员工添加到系统中,员工只能登录并查看部分数据。因此,正如我在 Java Spring 中理解的那样,员工 table 中的 user_id 等参数并未额外写入模型中。这就是我现在拥有的:
Employee.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
@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(创建员工函数)
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
@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);
}
我的邮递员POST请求添加员工:
{
"academic_title": "xy",
"department": "xx",
"user_id": 5
}
当我尝试将 user_id 保存为普通 Long 参数时,我可以将其保存到数据库中。但是当我获取现有员工时,连接功能不起作用,所以我看不到 user_id 5 是谁。
当我以另一种方式尝试时,就像上面的代码一样,我收到如下错误: not-null 属性 references a null or transient value
或类似的东西
员工列:user_id(应映射为 insert="false" update="false")。所以我不知道该怎么办,我在这个问题上卡了5天。
在此先感谢您的帮助!
如果您决定使用 Hibernate 和注解 @OneToOne
来定义您的关系,您现在应该牢记 Employee 有一个 class 属性(属性)用户。为了在用户 table 上存储来自员工 table 的外键,您需要将 User 实例设置为 Employee.
你应该在你的情况下尝试这样的事情:
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
User 和 Employee 之间的获取类型是 Lazy。这意味着它在加载员工时实际上并没有加载用户。相反,它会在请求时加载它们。
正如@Zooger 提到的,您应该先从数据库加载用户。
我是 Java Spring 的新手,我尝试了几天让我的关系正常运转,但没有成功。我正在使用 Java Spring 和 Mysql.
管理员应将员工添加到数据库中。员工将只能看到特定数据。我的问题是,我不明白如何从 EmployeesController 发出正确的 POST 请求并从用户模型中获取 user_id。我尝试了一些不同的实现,但仍然无法正常工作。
我有一个用户、角色和员工实体。员工始终是用户,但用户可能不是员工。所以我的数据库结构如下:
用户:
+----------+--------------+------+-----+---------+----------------+
| 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 |
+----------+--------------+------+-----+---------+----------------+
员工:
+-------------------+--------------+------+-----+---------+----------------+
| 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 | |
+-------------------+--------------+------+-----+---------+----------------+
只有管理员才能将员工添加到系统中,员工只能登录并查看部分数据。因此,正如我在 Java Spring 中理解的那样,员工 table 中的 user_id 等参数并未额外写入模型中。这就是我现在拥有的:
Employee.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
@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(创建员工函数)
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
@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);
}
我的邮递员POST请求添加员工:
{
"academic_title": "xy",
"department": "xx",
"user_id": 5
}
当我尝试将 user_id 保存为普通 Long 参数时,我可以将其保存到数据库中。但是当我获取现有员工时,连接功能不起作用,所以我看不到 user_id 5 是谁。 当我以另一种方式尝试时,就像上面的代码一样,我收到如下错误: not-null 属性 references a null or transient value 或类似的东西 员工列:user_id(应映射为 insert="false" update="false")。所以我不知道该怎么办,我在这个问题上卡了5天。
在此先感谢您的帮助!
如果您决定使用 Hibernate 和注解 @OneToOne
来定义您的关系,您现在应该牢记 Employee 有一个 class 属性(属性)用户。为了在用户 table 上存储来自员工 table 的外键,您需要将 User 实例设置为 Employee.
你应该在你的情况下尝试这样的事情:
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
User 和 Employee 之间的获取类型是 Lazy。这意味着它在加载员工时实际上并没有加载用户。相反,它会在请求时加载它们。
正如@Zooger 提到的,您应该先从数据库加载用户。