2010-01-04 64 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; 
    } 

}