我有两个对象Mat和MatImage,父母和孩子分别。 MatImage的主键是Mat的ID,它们之间是一对一的关系。

如果我正确理解了双向关系,那么如果我执行matImage.setMat(mat)之类的操作,子对象将了解父对象。我认为主键将在此时填充,但事实并非如此。我知道这是因为sql在尝试将#0作为matId插入MatImage时引发异常。

另一个问题是n + 1问题。我想延迟加载子对象,因为并非所有垫子都具有matimage。我可以尝试将@OneToOne更改为@ManyToOne,但不确定如何双向进行。任何帮助,将不胜感激。谢谢。

以下是实体:

// Mat

@Entity
@Table(name="mat")
public class Mat implements Serializable {
 @Id
 @GeneratedValue(generator="SeqMat")
 @SequenceGenerator(name="SeqMat", sequenceName="seq_mat_id")
    int id

    @OneToOne(mappedBy="mat", optional=true, fetch=FetchType.LAZY)
 @PrimaryKeyJoinColumn(name="id", referencedColumnName="matId")
 @Cascade([ALL, DELETE_ORPHAN])
 MatImage matImage

    int matTemplateId
    int number
    ...
}


     // MatImage
    @Entity
    @Table(name="matimage")
    public class MatImage implements Serializable {
        @Id
        int matId

        @OneToOne(optional=true, fetch=FetchType.LAZY)
        @JoinColumn(name="matId", referencedColumnName="id")
        Mat mat

        @Column(name="img_eventid")
        int eventId

        ...
}

最佳答案

我不确定你是否真的想要。但是,您可以使用以下类似方法来建立双向关系。

@Entity
public class Mat implements Serializable {

    private MutableInt id = new Mutable(-1);

    private MatImage matImage;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO, generator="SeqMat")
    @SequenceGenerator(name="SeqMat", sequenceName="seq_mat_id")
    public Integer getId() {
        return this.id.intValue;
    }

    public void setId(Integer id) {
        this.id.setValue(id)
    }

    public void setIdAsMutableInt(MutableInt id) {
        this.id = id;
    }

    @OneToOne(fetch=FetchType.LAZY)
    @PrimaryKeyJoinColumn
    @Cascade({CascadeType.ALL, CascadeType.DELETE_ORPHAN})
    public MatImage getMatImage() {
        return this.matImage;
    }

    public void setMatImage(MatImage matImage) {
        this.matImage = matImage;

        this.matImage.setIdAsMutableInt(this.id);
    }

}


现在我们的MatImage

@Entity
public class MatImage implements Serializable {

    private MutableInt id = new MutableInt(-1);

    private Mat mat;

    @Id
    public Integer getId() {
        return this.id.intValue();
    }

    public void setId(Integer id) {
        this.id.setValue(id);
    }

    public void setIdAsMutableInt(MutableInt id) {
        this.id = id;
    }

    @OneToOne(fetch=FetchType.LAZY)
    @PrimaryKeyJoinColumn
    public Mat getMat() {
        return mat;
    }

    public void setMat(Mat mat) {
        this.mat = mat;

        this.mat.setIdAsMutableInt(this.id);
    }

}


几点建议


JPA规范不包含处理共享主键生成问题的标准化方法


它解释了为什么我使用org.apache.commons.lang.mutable.MutableInt作为MatMatImage在内存中共享相同对象(id)的方式。

现在,您可以使用类似以下的内容:

Mat mat = new Mat();
MatImage matImage = new MatImage();

/**
  * Set up both sides
  *
  * Or use some kind of add convenience method To take car of it
  */
mat.setImage(matImage);
matImage.setMat(mat);

session.saveOrUpdate(mat);


两者将共享相同的生成ID。

建议:将注释配置放在getter方法中,而不是在成员字段中。 Hibernate使用代理对象。但是代理在getter方法中使用批注时效果很好,而不是在成员字段中使用时效果很好。

问候,

07-26 05:21