【问题标题】:Nullable @ManyToOne not accepting null value [duplicate]可空@ManyToOne 不接受空值 [重复]
【发布时间】:2019-01-29 20:02:16
【问题描述】:

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

@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 映射。我添加了一个关于它的答案,如果我遇到解决方法可能会进行编辑。

【问题讨论】:

  • 能否在问题中添加Profile pojo?
  • 先保存User,然后再添加到Profile 实体。还请确保在填充 UserProfile 时,将每个实体添加到另一个实体中,从而创建双向关系。
  • 只有当Usernull时才会出现错误,所以我不想添加它。我希望该字段为null
  • 你确定吗?因为Hibernate抱怨用户未保存!
  • 好吧,我刚刚结束了它的新调试,然后... 结果用户字段 不是 为空。 Mea culpa - 它试图添加一个User,所有字段都为空。太好了......现在的问题是:Userbe null 不应该吗?或者我错过了什么。

标签: java hibernate jpa mapstruct


【解决方案1】:

在我的机器上尝试了您的代码。以下是我的实体类:

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

【讨论】:

    【解决方案2】:

    因此,在对生成的文件进行一些挖掘之后:(目前)没有解决方案。问题来自实体 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;
    }
    

    所以...我将把问题一式两份。非常感谢帮助我的人(尽管如果我更加警惕,我就不需要发帖了)。

    【讨论】:

      猜你喜欢
      • 2014-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多