2010-01-04 154 views
4

我有兩個對象Mat和MatImage,父母和孩子resp。 MatImage的主鍵是Mat的id,它們通過一對一的關係進行連接。@PrimaryKeyJoinColumn與Bidirectional @OneToOne關係

如果我正確理解雙向關係,那麼如果我執行類似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 

     ... 
} 
+0

你使用Oracle ???你說過:當SQL嘗試以#0作爲matId插入MatImage時,SQL會引發異常。好的,但你能展示如何保存一個MatImage對象? – 2010-01-04 21:09:32

+0

實際上你的問題是什麼?清楚說明。 – Bozho 2010-01-05 04:50:58

+0

Mat設置爲MatImage之前保存了Mat嗎? – EJB 2010-01-05 09:36:07

回答

4

我不知道你真正想要的。但是您可以使用類似於以下內容的設置來建立雙向關係。

@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方法中使用註釋時,代理工作正常,而不是在成員字段中使用註釋。

問候,

3

的問題是,JPA,默認情況下,不會允許雙向,共享密鑰適當的註釋,一個一對一的關係。 Hibernate具有完美的構造,但請注意正確的順序以及註釋的具體參數(您也可以閱讀hibernate參考,但除非您先設置依賴對象,否則它們的示例將不起作用,用下面的方法避免這種方法 - 基本上可以自動保存這兩個對象,一次去除)。 在此示例中,每個作業正在處理一條消息。作業是「父母」,消息是依賴對象。消息的主鍵是作業ID(用於消除消息表中的一個額外列,如果需要使用作業範圍之外的消息,則可以在消息表中創建一個ID,使用與以下相同的設置) 。當作業創建並附加消息時,當jobDao.save被調用時,hibernate會自動保存兩個對象。

@Entity 
@Table 
public class Job implements Serializable{ 
private Long id; 
@Id 
    @GeneratedValue 
    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

@OneToOne(cascade = CascadeType.ALL, mappedBy = "job") 
    public Message getMessage() { 
     return message; 
    } 

    public void setMessage(Message message) { 
     this.message = message; 
     message.setJob(this); 
    } 
} 

而現在的依賴消息:

@Entity 
@Table 
public abstract class Message implements Serializable { 

private Job job; 

    @Id 
    @GeneratedValue(generator = "foreign") 
    @GenericGenerator(
      name = "foreign", 
      strategy = "foreign", 
      parameters = {@org.hibernate.annotations.Parameter(name = "property", value = "job")}) 
    @OneToOne(optional = false, cascade = CascadeType.ALL) 
    public Job getJob() { 
     return job; 
    } 

    public void setJob(Job job) { 
     this.job = job; 
    } 

}