可空@ManyToOne不接受空值

时间:2018-08-23 12:29:03

标签: java hibernate jpa mapstruct

我有一个多对一的关系,我想可以为空。 这是父母:

@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; 
}

还有孩子:

@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;
}

当我尝试保存没有userId的配置文件时,会引发以下错误:

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映射。我添加了有关此问题的答案,如果遇到解决方法,可能会进行编辑。

2 个答案:

答案 0 :(得分:0)

在我的计算机上尝试过您的代码。以下是我的实体类:

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;
}

用户类别:

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

答案 1 :(得分:0)

因此,在深入研究生成的文件之后:目前尚无解决方案。问题出在实体<-> 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;
}

所以...我将问题重复一遍。多亏了那些对我有帮助的人(尽管如果我更加警惕的话,我就不必发帖了)。