Nullable @ManyToOne 不接受空值
Nullable @ManyToOne not accepting null value
我有一个 many-to-one 关系,我希望它可以为空。
这是 parent:
@Entity
@Table(name = "C_CUSTOMER")
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToMany (fetch = FetchType.LAZY, mappedBy="user", cascade = CascadeType.REMOVE)
private List<Profile> profiles;
}
和 child:
@Entity
@Table(name = "C_PROFILE")
class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne(optional = true)
@JoinColumn(nullable = true, name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
private User user;
}
当我尝试保存没有用户 ID 的配置文件时,抛出以下错误:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : fr.entity.Profile.user -> fr.entity.User
如果userId这个字段有值,那就顺利了。
我在 SO 上尝试了其他问题的一系列答案,但到目前为止没有任何效果。最简单的方法是放弃实体文件中的关系并使用 Integer customerId
,但这对我来说并不是很令人满意,因为这意味着级联删除将不再起作用。
提前致谢。
编辑
问题来自实体 <-> dto 映射。我添加了一个关于它的答案,如果我遇到解决方法,可能会编辑。
在我的机器上试过你的代码。下面是我的实体 classes:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.Data;
@Entity
@Table(name = "C_PROFILE")
@Data
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToOne(optional = true)
@JoinColumn(nullable = true, name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
private User user;
}
用户class:
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.OneToMany;
import javax.persistence.Table;
import lombok.Data;
@Entity
@Table(name = "C_CUSTOMER")
@Data
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String email;
@OneToMany (fetch = FetchType.LAZY, mappedBy="user", cascade = CascadeType.REMOVE)
private List<Profile> profiles;
}
存储库:
import org.springframework.data.jpa.repository.JpaRepository;
import io.polarisdev.returns.model.Profile;
public interface ProfileRepository extends JpaRepository<Profile, String> {
}
在没有用户的情况下保存配置文件的代码:
Profile p = new Profile();
p.setName("Name");
profileRepository.save(p);
因此,在对生成的文件进行一些深入研究之后:目前还没有解决方案。问题来自实体 <-> dto 之间的映射,使用 mapstruct:没有提到这一步,难怪它没有像我应该的那样工作......好吧,配置文件映射器包含这个:
protected User profileToUser(Profile profile) {
if ( profile == null ) {
return null;
}
User user = new User();
User.setId(profile.getUserId());
return user;
}
意味着我需要在保存 Profile
之前重新分配一个空值。 github 上显然有关于此的票证,所以请拭目以待。似乎也有一些建议可以让它发挥作用,所以如果我遇到一个有效的建议,我会编辑这个答案(除非之前有人回答过解决方案)。
编辑
在对 mapstruct git 和 SO 进行了一些研究之后,我发现了一个可行的解决方案,尽管它并不是很优雅。
@AfterMapping
public Profile doAfterMapping(@MappingTarget Profile entity) {
if (entity != null && entity.getUser().getId() == null) {
entity.setUser(null);
}
return entity;
}
所以...我会把这个问题一式两份。非常感谢那些帮助过我的人(尽管如果我更加警惕,我就不需要 post)。
我有一个 many-to-one 关系,我希望它可以为空。 这是 parent:
@Entity
@Table(name = "C_CUSTOMER")
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@OneToMany (fetch = FetchType.LAZY, mappedBy="user", cascade = CascadeType.REMOVE)
private List<Profile> profiles;
}
和 child:
@Entity
@Table(name = "C_PROFILE")
class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne(optional = true)
@JoinColumn(nullable = true, name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
private User user;
}
当我尝试保存没有用户 ID 的配置文件时,抛出以下错误:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : fr.entity.Profile.user -> fr.entity.User
如果userId这个字段有值,那就顺利了。
我在 SO 上尝试了其他问题的一系列答案,但到目前为止没有任何效果。最简单的方法是放弃实体文件中的关系并使用 Integer customerId
,但这对我来说并不是很令人满意,因为这意味着级联删除将不再起作用。
提前致谢。
编辑
问题来自实体 <-> dto 映射。我添加了一个关于它的答案,如果我遇到解决方法,可能会编辑。
在我的机器上试过你的代码。下面是我的实体 classes:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.Data;
@Entity
@Table(name = "C_PROFILE")
@Data
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToOne(optional = true)
@JoinColumn(nullable = true, name = "user_id", referencedColumnName = "id", insertable = false, updatable = false)
private User user;
}
用户class:
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.OneToMany;
import javax.persistence.Table;
import lombok.Data;
@Entity
@Table(name = "C_CUSTOMER")
@Data
class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String email;
@OneToMany (fetch = FetchType.LAZY, mappedBy="user", cascade = CascadeType.REMOVE)
private List<Profile> profiles;
}
存储库:
import org.springframework.data.jpa.repository.JpaRepository;
import io.polarisdev.returns.model.Profile;
public interface ProfileRepository extends JpaRepository<Profile, String> {
}
在没有用户的情况下保存配置文件的代码:
Profile p = new Profile();
p.setName("Name");
profileRepository.save(p);
因此,在对生成的文件进行一些深入研究之后:目前还没有解决方案。问题来自实体 <-> dto 之间的映射,使用 mapstruct:没有提到这一步,难怪它没有像我应该的那样工作......好吧,配置文件映射器包含这个:
protected User profileToUser(Profile profile) {
if ( profile == null ) {
return null;
}
User user = new User();
User.setId(profile.getUserId());
return user;
}
意味着我需要在保存 Profile
之前重新分配一个空值。 github 上显然有关于此的票证,所以请拭目以待。似乎也有一些建议可以让它发挥作用,所以如果我遇到一个有效的建议,我会编辑这个答案(除非之前有人回答过解决方案)。
编辑
在对 mapstruct git 和 SO 进行了一些研究之后,我发现了一个可行的解决方案,尽管它并不是很优雅。
@AfterMapping
public Profile doAfterMapping(@MappingTarget Profile entity) {
if (entity != null && entity.getUser().getId() == null) {
entity.setUser(null);
}
return entity;
}
所以...我会把这个问题一式两份。非常感谢那些帮助过我的人(尽管如果我更加警惕,我就不需要 post)。