马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?FreeOZ用户注册
x
实体之间有One-To-One, One-To-Many, Many-To-One, Many-To-Many的关系。
其中单单是One-To-One又可以分成unidirection, bi-direction两种。
就unidirection来看,很明显,这里可以分成主从两个实体,主实体里可以找到从实体的
对象,而从实体对于主实体可以说是一无所知的。在程序对象中,这个关系很容易表达,
只要在主实体类中结合一个从实体对象即可;而在数据库中,这种关系往往可以由
Foreign-Key来实现:Foreign-Key在哪一个表中,那么这个表就是主表,另一个表
则是从表。
但有的时候,情况是这样的:如果从表没有建立自己的独立主键,而直接使用主表的主键
作为自己的主键,这样,主表只需要在从表里查找那条包含了自己主键值的记录即可;
这种情况不需要别外附加一个新的外键。
对于上面两种情况,在EJB Entity技术中有两个对应的Annotation:
@JoinColumn
@PrimaryKeyJoinColumn
我们来看看它们是怎样实现和操作的。为了简化程序,我把两种情况在同一个Entity中实现了。
主实体- 1 package persistence2;
- 2
- 3 import javax.persistence.*;
- 4
- 5 @Entity
- 6 @Table(name="USER")
- 7 public class MyUserEntity{
- 8 private Long id;
- 9 private String name;
- 10 private MyAddressEntity address;
- 11 private MyBirthdayEntity birth;
- 12
- 13 @Id
- 14 @GeneratedValue(strategy=GenerationType.AUTO)
- 15 @Column(name="USER_ID", insertable=false, updatable=false)
- 16 public Long getId() {
- 17 return id;
- 18 }
- 19
- 20 public void setId(Long id){
- 21 this.id = id;
- 22 }
- 23
- 24 @Column(name="USER_NAME", nullable=false, updatable=false)
- 25 public String getName() {
- 26 return name;
- 27 }
- 28
- 29 public void setName(String name){
- 30 this.name = name;
- 31 }
- 32
- 33 @OneToOne
- 34 @PrimaryKeyJoinColumn(name="USER_ID",
- 35 referencedColumnName="BILLING_USER_ID")
- 36 public MyAddressEntity getAddress() {
- 37 return address;
- 38 }
- 39
- 40 public void setAddress(MyAddressEntity address){
- 41 this.address = address;
- 42 }
- 43
- 44 @OneToOne
- 45 @JoinColumn(name="USER_BIRTH_ID", referencedColumnName="BIRTH_ID")
- 46 public MyBirthdayEntity getBirth() {
- 47 return birth;
- 48 }
- 49
- 50 public void setBirth(MyBirthdayEntity birth) {
- 51 this.birth = birth;
- 52 }
- 53
- 54 }
复制代码 使用@JoinColumn的从实体- 1 package persistence2;
- 2
- 3 import javax.persistence.*;
- 4
- 5 @Entity
- 6 @Table(name="BIRTHDAY")
- 7 public class MyBirthdayEntity {
- 8 private Long id;
- 9 private java.util.Date date;
- 10
- 11 @Id
- 12 @GeneratedValue(strategy=GenerationType.AUTO)
- 13 @Column(name="BIRTH_ID")
- 14 public Long getId() { return id; }
- 15
- 16 public void setId(Long id) { this.id = id; }
- 17
- 18 @Column(name="BIRTH_DATE")
- 19 @Temporal(value=TemporalType.DATE)
- 20 public java.util.Date getDate() { return date; }
- 21
- 22 public void setDate(java.util.Date date) { this.date = date; }
- 23 }
复制代码 使用@PrimaryKeyJoinColumn的从实体- 1 package persistence2;
- 2
- 3 import javax.persistence.*;
- 4
- 5 @Entity
- 6 @Table(name="ADDRESS")
- 7 public class MyAddressEntity {
- 8 private Long userId;
- 9 private String street;
- 10 private String suburn;
- 11
- 12 @Id
- 13 @Column(name="BILLING_USER_ID")
- 14 public Long getUserId() {
- 15 return userId;
- 16 }
- 17
- 18 public void setUserId(Long id){
- 19 userId = id;
- 20 }
- 21
- 22 @Column(name="BILLING_STREET")
- 23 public String getStreet()
- 24 {
- 25 return street;
- 26 }
- 27
- 28 public void setStreet(String street)
- 29 {
- 30 this.street = street;
- 31 }
- 32
- 33 @Column(name="ADDRESS_SUBURN")
- 34 public String getSuburn() {
- 35 return suburn;
- 36 }
- 37
- 38 public void setSuburn(String suburn){
- 39 this.suburn = suburn;
- 40 }
- 41
- 42 }
- 43
复制代码 操作实体的Session Bean程序(部分)- 50 MyUserEntity user = new MyUserEntity();
- 51 MyAddressEntity address = new MyAddressEntity();
- 52 MyBirthdayEntity birth = new MyBirthdayEntity();
- 53
- 54 birth.setDate(new java.util.Date());
- 55 address.setStreet("Doomben Ave");
- 56 address.setSuburn("Eastwood");
- 57 user.setName("Key");
- 58 user.setAddress(address);
- 59 user.setBirth(birth);
- 60
- 61 manager.persist(user);
- 62 address.setUserId(user.getId());
- 63 manager.persist(address);
- 64 manager.persist(birth);
复制代码 这里需要注意的是程序62行,我们需要通过manager.persist(user)来materialize
user对象,然后才能获得一个id值(注意@GeneratedValue(strategy=GenerationType.AUTO))
然后再才这个id值赋给address对象。
有几种出错的可能:
1. address.userid没有赋值,这样就不能直接存放
2. address或birth两个对象之一或全部没有persist()到数据库中,程序执行不成功,
在结束这个方法的时候会抛出rollback
现在再看看数据库中的情况:
user表- create table USER (USER_ID bigint generated by default as identity (start with 1), USER_NAME varchar(255) not null, USER_BIRTH_ID bigint, primary key (USER_ID))
复制代码 birthday表- create table BIRTHDAY (BIRTH_ID bigint generated by default as identity (start with 1), BIRTH_DATE date, primary key (BIRTH_ID))
复制代码 address表- create table ADDRESS (BILLING_USER_ID bigint not null, BILLING_STREET varchar(255), ADDRESS_SUBURN varchar(255), primary key (BILLING_USER_ID))
复制代码 user与birthday的外键- alter table USER add constraint FK27E3CB1C269356 foreign key (USER_BIRTH_ID) references BIRTHDAY
复制代码 注意到,这里从user到address之间是没有外键的,他们之间采用的是primary到primary的直接关联,
换句话说,address的主键就是外键。
如果一定要建立bi-direction关系,只需要在从实体类中做手脚即可
改变后的address类- 1 package persistence2;
- 2
- 3 import javax.persistence.*;
- 4
- 5 @Entity
- 6 @Table(name="ADDRESS")
- 7 public class MyAddressEntity {
- 8 private Long userId;
- 9 private String street;
- 10 private String suburn;
- 11 private MyUserEntity user;
- 12
- 13 @Id
- 14 @Column(name="BILLING_USER_ID")
- 15 public Long getUserId() {
- 16 return userId;
- 17 }
- 18
- 19 public void setUserId(Long id){
- 20 userId = id;
- 21 }
- 22
- 23 @Column(name="BILLING_STREET")
- 24 public String getStreet()
- 25 {
- 26 return street;
- 27 }
- 28
- 29 public void setStreet(String street)
- 30 {
- 31 this.street = street;
- 32 }
- 33
- 34 @Column(name="ADDRESS_SUBURN")
- 35 public String getSuburn() {
- 36 return suburn;
- 37 }
- 38
- 39 public void setSuburn(String suburn){
- 40 this.suburn = suburn;
- 41 }
- 42
- 43 @OneToOne(mappedBy="address")
- 44 public MyUserEntity getUser() { return user; }
- 45
- 46 public void setUser(MyUserEntity user) { this.user = user; }
- 47
- 48 }
复制代码 改变后的birthday类- 1 package persistence2;
- 2
- 3 import javax.persistence.*;
- 4
- 5 @Entity
- 6 @Table(name="BIRTHDAY")
- 7 public class MyBirthdayEntity {
- 8 private Long id;
- 9 private java.util.Date date;
- 10 private MyUserEntity user;
- 11
- 12 @Id
- 13 @GeneratedValue(strategy=GenerationType.AUTO)
- 14 @Column(name="BIRTH_ID")
- 15 public Long getId() { return id; }
- 16
- 17 public void setId(Long id) { this.id = id; }
- 18
- 19 @Column(name="BIRTH_DATE")
- 20 @Temporal(value=TemporalType.DATE)
- 21 public java.util.Date getDate() { return date; }
- 22
- 23 public void setDate(java.util.Date date) { this.date = date; }
- 24
- 25 @OneToOne(mappedBy="birth")
- 26 public MyUserEntity getUser() { return user; }
- 27
- 28 public void setUser(MyUserEntity user) { this.user = user; }
- 29 }
复制代码 改变后的Session Bean- 50 MyUserEntity user = new MyUserEntity();
- 51 MyAddressEntity address = new MyAddressEntity();
- 52 MyBirthdayEntity birth = new MyBirthdayEntity();
- 53
- 54 birth.setDate(new java.util.Date());
- 55 address.setStreet("Doomben Ave");
- 56 address.setSuburn("Eastwood");
- 57 user.setName("Key");
- 58 user.setAddress(address);
- 59 user.setBirth(birth);
- 60
- 61 birth.setUser(user);
- 62 address.setUser(user);
- 63
- 64 manager.persist(user);
- 65 address.setUserId(user.getId());
- 66 manager.persist(address);
- 67 manager.persist(birth);
复制代码 这里有一个问题:
1. mappedBy中指出的不是对应的“表字段”名称,而是类属性名称
再看一下数据库的情况,和之前是一模一样,没有改变。
可以想到,bi-direction与unidirection是程序上的概念,而不是数据库存贮的概念,
这个需要注意了。 |