具有@IdClass注释的类中的可插入对象

时间:2017-01-24 14:40:19

标签: java hibernate jpa annotations java-persistence-api

是否可以在Section.class中进行级联保存? 我创建了Section对象并添加了没有id的新问题。 当我尝试保存时,我收到错误:

  

org.postgresql.util.PSQLException:错误:在表格上插入或更新   “question_to_section”违反了外键约束   “fk_2br9f09ok965403a9rv5y2n10”详细信息:键(question_id)=(0)不是   出现在表格“问题”中。

我也尝试使用@Embedded注释,但没有成功。

科级:

@Table(name = "section")
@Entity(name = "section")
public class Section implements Serializable{   

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id",    unique = true, nullable = false)
    @JsonProperty
    long id;    

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "section")
    Set<QuestionToSection> questions = new HashSet<QuestionToSection>(0);
    ...
}

问题到科级

@Entity(name = "question_to_section")
@Table(name = "question_to_section")
@IdClass(QuestionSectionId.class)
public class QuestionToSection implements Serializable {

    @Id
    long sectionId;

    @Id
    long questionId;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "sectionId", nullable = false, updatable = false, insertable = false, referencedColumnName = "id")
    Section section;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL )
    @JoinColumn(name = "questionId", nullable = false, updatable = false, insertable = false, referencedColumnName = "id")
    Question question;
    ...
}

QuestionSectionId

public class QuestionSectionId implements Serializable {

    long questionId;
    long sectionId; 

}

2 个答案:

答案 0 :(得分:0)

您应该从班级insertable = false中的@JoinColumn中移除QuestionToSection。你正在覆盖级联插入这样做,所以JPA不会插入,如果他们不存在。只需从注释中删除可插入内容即可解决问题。

答案 1 :(得分:0)

数据库中的每个表都不必映射到实体。特别是,纯连接表通常更好地映射为实体。对于多对多关系,例如:

@Table(name = "section")
public class Section implements Serializable{   

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    @JsonProperty
    long id;    

    // Note: probably do not want to cascade REMOVE operations
    @ManyToMany(fetch = FetchType.LAZY,
        cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH},
        mappedBy = "sections")
    @JoinTable(
        name = "question_to_section"
        joinColumns =
            @JoinColumn(name="sectionId", referencedColumnName="ID"),
        inverseJoinColumns=
            @JoinColumn(name="questionId", referencedColumnName="ID")
    )
    Set<Question> questions = new HashSet<Question>(0);
    ...
}

假定双向关系,在实体Question中有相应的注释;对于单向,请删除mappedBy的{​​{1}}属性。无论哪种方式,这都可以减轻您直接管理ManyToMany表的麻烦,并减少系统中离散实体的数量。

另一方面,如果您需要一个真正的 question_to_entity弱实体 - ,如果实例具有问题和部分之外的其他属性 - 那么你确实遇到级联持久性问题。您要做的是将多个实体属性映射到数据库中的同一列,从而提供不一致的机会。

如果涉及的QuestionToSectionQuestion实体中的一个或两个是新的,那么 是不一致的,因此它还没有ID。 JPA无法知道它应该从关联的SectionQuestionToSection实体的ID中设置Question的id字段。当他们收到自动生成的ID时,与其关联的Section实体将变得不一致。

可以想象,您可以通过在QuestionToSection上设置@Access(AccessType = PROPERTY),并使用持久属性访问器方法玩游戏来解决此问题,但这有点令人讨厌。如果你确实需要一个弱实体,那么最好不要尝试级联QuestionToSection操作,尽管你可以级联其他操作。实际上,在这种情况下,您可能希望将PERSIST操作级联到弱实体,而不是级联到其他关联实体。