Java Hibernate级联-Hibernate先保存父级,再保存子级
我想使用SpringDataJPA在数据库中保存一个新的UserRegistration实例。在数据库中,我有表“用户”和“权限”。每次尝试保存实例时,都会出现错误“无法” 添加或更新子行:外键约束失败”。这是因为表“authorities”包含引用“users”的外键。导致此错误的原因是,在插入UserRegistration实例之前,Hibernate首先尝试存储授权实例:Java Hibernate级联-Hibernate先保存父级,再保存子级,java,spring,hibernate,web,cascade,Java,Spring,Hibernate,Web,Cascade,我想使用SpringDataJPA在数据库中保存一个新的UserRegistration实例。在数据库中,我有表“用户”和“权限”。每次尝试保存实例时,都会出现错误“无法” 添加或更新子行:外键约束失败”。这是因为表“authorities”包含引用“users”的外键。导致此错误的原因是,在插入UserRegistration实例之前,Hibernate首先尝试存储授权实例: Hibernate: insert into users (ema
Hibernate:
insert
into
users
(email, enabled, password, profilePicture, username)
values
(?, ?, ?, ?, ?)
Hibernate:
insert
into
authorities
(authority, username, userid)
values
(?, ?, ?)
UserRegistration.java:
package main.java.de.ostfalia.seprojekt.database.models;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import main.java.de.ostfalia.seprojekt.database.dto.UserRegistrationDTO;
@Entity
@Table(name = "users")
public class UserRegistration {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
@JsonIgnore
private String password;
@JsonIgnore
private boolean enabled;
private Integer profilePicture;
private String email;
@OneToOne(fetch = FetchType.LAZY, optional = false, mappedBy = "user", cascade = CascadeType.ALL)
private Authority authority;
@JsonManagedReference
@ManyToMany
@JoinTable(name = "userhasfavorite", joinColumns = @JoinColumn(name = "userid"), inverseJoinColumns = @JoinColumn(name = "channelid"))
private List<Channel> favorites;
public UserRegistration() {
}
public UserRegistration(UserRegistrationDTO dto) {
this.email = dto.getEmail();
this.username = dto.getUsername();
this.password = dto.getPassword();
this.enabled = dto.isEnabled();
this.profilePicture = dto.getProfilePicture();
this.authority = new Authority(id, username, dto.getRole(), this);
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean getEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Integer getProfilePicture() {
return profilePicture;
}
public void setProfilePicture(Integer profilePicture) {
this.profilePicture = profilePicture;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Authority getAuthority() {
return authority;
}
public void setAuthority(Authority authority) {
this.authority = authority;
}
public List<Channel> getFavorites() {
return favorites;
}
public void setFavorites(List<Channel> favorites) {
this.favorites = favorites;
}
}
保存实体的代码:
@PostMapping
public boolean saveUser(@RequestBody UserRegistrationDTO userToSave) {
if (roleExists(userToSave.getRole())) {
UserRegistration user = new UserRegistration(userToSave);
uRepo.saveAndFlush(user);
return true;
}
return false;
}
我现在的问题是:在使用CascadeTypes插入授权实例之前,如何保存UserRegistration实例
谢谢你阅读这个问题。我期待着解决此问题。您可能应该将
mappedBy
属性移动到关联的另一端,因为您希望UserRegistration
成为关联的所有者(它首先持续存在)。此外,您想在此处使用@PrimaryKeyJoinColumn
而不是@JoinColumn
。问题是我还想删除与所属机构的用户注册。如果我传输mappedby属性,Hibernate将首先删除UserRegistration,这也会导致违反外键约束。你知道这个问题的解决方案吗?从这个角度看,这个映射在我看来肯定是可疑的。我建议将其与在线资源中描述良好的一对一映射进行比较。我认为您的映射无效,这会导致关联方向错误,从而导致Hibernate尝试以错误的顺序插入。还存在一些与删除一对一关联相关的错误,因此请确保您使用的是最新版本的Hibernate(理想情况下,最近的5.4.x、OneTONE映射在5.3.x IMO上相当失败-我为5.4提供了至少3-4个错误修复)。您使用的是哪个版本?正如您所说,我转移了mappedBy属性。我还在这个类中移动了CascadeType。现在我得到了错误“对象引用未保存的临时实例-在刷新之前保存临时实例"因为用户实例引用了尚未保存的授权实例。可能我必须手动执行此操作。我使用Spring Data JPA版本2.3。Spring Data JPA使用Hibernate,但我不知道是哪个版本。您可能应该将mappedBy
属性移动到关联的另一端,因为您需要UserRegistrate在
上成为关联的拥有方(首先保持)。此外,您想在此处使用@PrimaryKeyJoinColumn
而不是@JoinColumn
。问题是我还想删除与所属机构的用户注册。如果我转移了mappedby属性,Hibernate将首先删除用户注册,这也会导致违反外键约束。您认为呢知道这个问题的解决方案吗?从外观上看,映射对我来说肯定是可疑的。我建议将其与在线资源中描述良好的两个一对一映射进行比较。我认为您的映射无效,这导致关联方向错误,这导致Hibernate尝试插入错误的映射顺序。还存在一些与删除一对一关联相关的错误,因此请确保在最新版本的Hibernate上(理想情况下,最新的5.4.x、OneToOne映射在5.3.x IMO上被完全破坏-我在5.4中至少修复了3-4个错误).您使用的是哪个版本?正如您所说,我传输了mappedBy属性。我还在这个类中移动了CascadeType。现在我得到错误“对象引用了一个未保存的临时实例-在刷新之前保存临时实例”因为用户实例引用了一个尚未保存的授权实例。可能我必须手动执行此操作。我使用Spring Data JPA 2.3版。Spring Data JPA使用Hibernate,但我不知道是哪个版本。
@PostMapping
public boolean saveUser(@RequestBody UserRegistrationDTO userToSave) {
if (roleExists(userToSave.getRole())) {
UserRegistration user = new UserRegistration(userToSave);
uRepo.saveAndFlush(user);
return true;
}
return false;
}