eclipse + JBoss 5 + EJB3开发指南(7):实现Entity Bean的一对一(on

本文为原创,如需转载,请注明作者和出处,谢谢!

    一对一映射是很常用的。在一般情况下,一个主表通过外键和从表形成一对一的关系。在EJB3中使用@OneToOne注释来映射。一对一关系除了使用外键进行关联外,也可以采用共享主键的方式连接两个表。先看看如下两个表的结构:

eclipse + JBoss 5 + EJB3开发指南(7):实现Entity Bean的一对一(on
图1  t_customers
eclipse + JBoss 5 + EJB3开发指南(7):实现Entity Bean的一对一(on

图2  t_referees

    t_customers和t_referees表形成了一对一的关系。t_customers表通过referee_id与t_referees表相连。与t_customers表对应的实体Bean的代码如下:

Code:
  1. package entity;  
  2.   
  3. import java.util.Collection;  
  4. import javax.persistence.Entity;  
  5. import javax.persistence.FetchType;  
  6. import javax.persistence.GeneratedValue;  
  7. import javax.persistence.GenerationType;  
  8. import javax.persistence.Id;  
  9. import javax.persistence.JoinColumn;  
  10. import javax.persistence.OneToOne;  
  11. import javax.persistence.Table;  
  12.   
  13. @Entity  
  14. @Table(name = "t_customers")  
  15. public class Customer  
  16. {  
  17.     private int id;  
  18.     private String name;  
  19.     private Referee referee;  
  20.   
  21.     @Id  
  22.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  23.     public int getId()  
  24.     {  
  25.         return id;  
  26.     }  
  27.     public void setId(int id)  
  28.     {  
  29.         this.id = id;  
  30.     }  
  31.   
  32.     public String getName()  
  33.     {  
  34.         return name;  
  35.     }  
  36.   
  37.     public void setName(String name)  
  38.     {  
  39.         this.name = name;  
  40.     }  
  41.   
  42.     @OneToOne  
  43.     public Referee getReferee()  
  44.     {  
  45.         return referee;  
  46.     }  
  47.     public void setReferee(Referee referee)  
  48.     {  
  49.         this.referee = referee;  
  50.     }  

    从上面的代码可以看出,getReferee方法使用了@OneToOne进行设置。在装载Customer对象的同时,Referee对象会被同时装 载,而默认的外键字段就是Customer类中的referee属性名 + "_" + id,也就是referee_id。下面看一下与t_referees表对应的实体Bean代码:

Code:
  1. package entity;  
  2.   
  3. import javax.persistence.Entity;  
  4. import javax.persistence.GeneratedValue;  
  5. import javax.persistence.GenerationType;  
  6. import javax.persistence.Id;  
  7. import javax.persistence.JoinColumn;  
  8. import javax.persistence.OneToOne;  
  9. import javax.persistence.Table;  
  10.   
  11. @Entity  
  12. @Table(name="t_referees")  
  13. public class Referee  
  14. {  
  15.     private int id;  
  16.     private String name;  
  17.     private Customer customer;  
  18.     @OneToOne(mappedBy="referee")  
  19.     public Customer getCustomer()  
  20.     {  
  21.         return customer;  
  22.     }  
  23.   
  24.     public void setCustomer(Customer customer)  
  25.     {  
  26.         this.customer = customer;  
  27.     }  
  28.   
  29.     @Id  
  30.     @GeneratedValue(strategy = GenerationType.IDENTITY)  
  31.     public int getId()  
  32.     {  
  33.         return id;  
  34.     }  
  35.     public void setId(int id)  
  36.     {  
  37.         this.id = id;  
  38.     }  
  39.     public String getName()  
  40.     {  
  41.         return name;  
  42.     }  
  43.   
  44.     public void setName(String name)  
  45.     {  
  46.         this.name = name;  
  47.     }  

    Referee类使用了customer属性映射了Customer对象,实际上,这是一个双向的one-to-one映射。这时,在Referee类的 customer属性的getter方法的@OneToOne注释中,需要使用mappedBy属性来指定主表(Customer)中的映射从表的属性名 (referee)。
    我们可以使用下面的代码进行测试:

Code:
  1. System.out.println(em.find(Referee.class1).getCustomer().getName());  
  2. Customer customer = new Customer();  
  3. customer.setName("微软");  
  4. Referee referee = new Referee();  
  5. referee.setName("赵军");  
  6. em.persist(referee);          
  7. customer.setReferee(referee);  
  8. em.persist(customer); 

    如果要覆盖默认的名键名,例如,外键名为referee1_id,可以两种方法使EJB3容器使用新的外键:
    1.  修改Customer类中的referee属性的getter和setter方法为getReferee1和setReferee1,并将Referee类中mappedBy属性的值修改成referee1。
    2.  使用@JoinColumn注释设置新的外键名,这种方法只需要修改Customer类的getReferee方法上面注释即可,代码如下:

Code:
  1. @OneToOne  
  2. @JoinColumn(name="referee1_id")  
  3. public Referee getReferee()  
  4. {  
  5.     return referee;  

    one-to-one关系还可以共享主键,也就是一个表的主键的值依赖于另一个表的主键的值。因此,在这种情况下,就不再需要t_customers表中 的referee_id字段了。由于t_referees表的id字段值依赖于t_customers表的id字段值,因此,需要将t_referees 表中的id字段值的自增类型去掉。
    在EJB3中使用@PrimaryKeyJoinColumn注释来实现主键的共享。首先需要修改Customer类的getReferee方法上方的注释,修改后的代码如下:

Code:
  1. @OneToOne(cascade=CascadeType.ALL)  
  2. @PrimaryKeyJoinColumn  
  3. public Referee getReferee()  
  4. {  
  5.     return referee;  
  6. }  


    然后要修改Referee类中的getCustomer和getId方法上方的注释,修改后的代码如下:

Code:
  1. @OneToOne  
  2. @PrimaryKeyJoinColumn  
  3. public Customer getCustomer()  
  4. {  
  5.     return customer;  
  6. }  
  7.   
  8. @Id  
  9. @GeneratedValue(generator = "pkGenerator")  
  10. @GenericGenerator(name = "pkGenerator", strategy = "foreign",  
  11.    parameters = @Parameter(name = "property", value = "customer"))  
  12. public int getId()  
  13. {  
  14.     return id;  

    其中@GenericGenerator注释表示这个id属性是外键,并且依赖于customer属性对应的实体Bean的id属性值(主键值)。
    另外还要注意一点,由于t_referees表的id的自增类型已经去掉,而且该值依赖于t_customers表的id字段值,因此,就不能直接持久化Referee对象了,而在持久化Customer对象的同时,EJB3容器会自动将Referee持久化的。

上一篇:[8.10更新日志]增加Node6.3编译语言支持,优化工作流配置


下一篇:Android弹幕编程设计实现的解决方案(一)