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)。