随笔-9  评论-168  文章-266  trackbacks-0
Hibernate Annotation几种关联映射
一对一(One-To-One)
使用@OneToOne注解建立实体Bean之间的一对一关联。一对一关联有三种情况:(1).关联的实体都共享同样的主键,(2).其中一个实体通过外键关联到另一个实体的主键(注意要模拟一对一关联必须在外键列上添加唯一约束),(3).通过关联表来保存两个实体之间的连接关系(要模拟一对一关联必须在每一个外键上添加唯一约束)。
 
1.共享主键的一对一关联映射:
@Entity
@Table(name="Test_Body")
public class Body {
   private Integer id;
   private Heart heart;
   @Id
   public Integer getId() {
      return id;
   }
   public void setId(Integer id) {
      this.id = id;
   }
   @OneToOne
   @PrimaryKeyJoinColumn
   public Heart getHeart() {
      return heart;
   }
   public void setHeart(Heart heart) {
      this.heart = heart;
   }
}
@Entity
@Table(name="Test_Heart")
public class Heart {
   private Integer id;
   @Id
   public Integer getId() {
      return id;
   }
   public void setId(Integer id) {
      this.id = id;
   }
}
通过@PrimaryKeyJoinColumn批注定义了一对一关联
 
2.使用外键进行实体一对一关联:
@Entity
@Table(name="Test_Trousers")
public class Trousers {
   @Id
   public Integer id;
   @OneToOne
   @JoinColumn(name = "zip_id")
   public TrousersZip zip;
}
@Entity
@Table(name="Test_TrousersZip")
public class TrousersZip {
   @Id
   public Integer id;
   @OneToOne(mappedBy = "zip")
   public Trousers trousers;
}
上面的例子是指Trousers通过Trousers的外键列zip_id和TrousersZip关联,@JoinColumn批注定义了联接列,该批注和@Column批注有点类似,但是多了一个名为referencedColumnName的参数。该参数定义了所关联目标实体中的联接列,注意,当referencedColumnName关联到非主键列的时候,关联的目标类必须实现Serializable,还要注意的是所映像的属性对应单个列(否则映射无效)
一对一关联可能是双向的,在双向关联中,有且仅有一端作为主体(owner)端存在:主体端负责维护联接列(即更新),对于不需要维护这种关系的从表则通过mappedNy属性进行声明。mappedBy的值指向主体的关联属性。例子中,mappedBy的值为zip。最后,不必也不能再在被关联端(ownedside)定义联接列了,因为已经在主体端声明了。
如果在主体没有声明@JoinColumn,系统自动进行处理:在主表(owner table)中将创建联接列,列名为:主体的关联属性名+下划线+被关联端的主键列名。上面的例子中是zip_id,因为Trousers中的关联属性名为zip,TrousersZip的主键是id。
 
3.通过关联表定义一对一关联
@Entity
@Table(name="Test_People")
public class People {
   @Id
   public Integer id;
   @OneToOne
   @JoinTable(name ="TestPeoplePassports",
      joinColumns =@JoinColumn(name="people_fk"),
      inverseJoinColumns =@JoinColumn(name="passport_fk")
   )
   public Passport passport;
}
@Entity
@Table(name="Test_Passport")
public class Passport {
   @Id
   public Integer id;
   @OneToOne(mappedBy = "passport")
   public People people;
}
People通过名为TestPeoplePassports的关联表和Passport关联。该关联表拥有名为passport_fk的外键列,该外键指向Passport表,该信息定义为inverseJoinColoumns的属性值,而people_fk外键列指向People表,该信息定义为joinColumns的属性值。
这种关联可能是双向的,在双向关联中,有且仅有一端作为主体(owner)端存在:主体端负责维护联接列(即更新),对于不需要维护这种关系的从表则通过mappedNy属性进行声明。mappedBy的值指向主体的关联属性。例子中,mappedBy的值为passport。最后,不必也不能再在被关联端(ownedside)定义联接列了,因为已经在主体端声明了。
以上是一对一关联的三种形式,下面介绍多对一关联。
 
 
 
多对一(Many-to-One)
使用@ManyToOne批注来实现多对一关联。
@ManyToOne批注有一个名为targetEntity的参数,该参数定义了目标实体名,通常不需要定义该参数,因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足需求了。不过下面这种情况下这个参数就显得有意义了:使用接口作为返回值而不是常见的实体。
@ManyToOne(targetEntity=CompanyImpl.class)
@JoinColoumn(name=”COPM_ID”)
Public Company getCompany(){
   return company;
}
多对一的配置方式有两种:(1)通过@JoinColoumn映像(2)通过关联表的方式来映像
 
(1)           通过@JoinColoumn映射
SRD Framework中Company,Category例子:
Company:
@ManyToOne
   @JoinColumn(name = "CATEGORY_OPTION_ID")
   private Category category = null;
   Category:
@DiscriminatorValue("Category")
public class Category extends Option {
}
(2)           通过关联表映射
通过@JoinTable批注定义关联表,该关联表包含了指回实体表的外键(通过@JoinTable.joinColoumns)以及指向目标实体表的外键(通过@JoinTable.inverseJoinColoumns)
@Entity
@Table(name="Test_TreeType")
public class TreeType {
   private Integer id;
   private String name;
   private ForestType forestType;
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinTable(name="Test_Tree_Forest",
      joinColumns = @JoinColumn(name="tree_id"),
      inverseJoinColumns = @JoinColumn(name="forest_id") )
public ForestType getForestType() {// forestType的getter,setter方法必须在这里,否则会出错
      return forestType;
   }
   public void setForestType(ForestType forestType) {
      this.forestType = forestType;
   }
   @Id
   @GeneratedValue
   public Integer getId() {
      return id;
   }
   public void setId(Integer id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}
@Entity
@Table(name="Test_ForestType")
public class ForestType {
   private Integer id;
   private String name;
   private Set<TreeType> trees;
   @OneToMany(mappedBy="forestType")
public Set<TreeType> getTrees() {// trees的getter,setter方法必须在这里,否则会出错
      return trees;
   }
   public void setTrees(Set<TreeType> trees) {
      this.trees = trees;
   }
   @Id @GeneratedValue
   public Integer getId() {
      return id;
   }
   public void setId(Integer id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}
 
一对多(One-to-Many)
使用@OneToMany批注可定义一对多关联,一对多关联可以是双向关联。
在EJB3规范中多对一这端几乎总是双向关联中的主体(owner)端,而一对多这端关联批注为@OneToMany(mappedBy...)
@Entity
Public class Troop{
   @OneToMany(mappedBy=”troop”)
Public Set<Soldier> getSoldiers(){
......
}
@Entity
Public class Soldier{
   @ManyToOne
   @JoinColumn(name=”troop_fk”)
Public Troop getTroop(){
......
}
Troop通过troop属性和Soldier建立一对多的双向关联,在mappedBy端不必也不能再定义任何物理映射。
对于一对多的双向映射,如果要一对多这一端维护关联关系,你需要删除mappedBy元素并将多对一这端的@JoinColoumn的insertable和updatabel设置为false。这种方案不会得到什么明显的优化,而且还会增加一些附加的UPDATE语句。
 
单向:
通过在被拥有的实体端(owned entity)增加一个外键列来实现一对多单向关联是很少见的,也是不推荐的,建议通过一个联接表来实现这种关联(下面会讲到)。
@JoinColoumn批注来描述这种单向关联关系
@Entity
Public class Customer{
   @OneToMany
@JoinColoumn(name=”CUST_ID”)
Public Set<ticket> getTickets() {
......
}
@Entity
Public class Ticket{
   ...
}
Customer通过CUST_ID列和Ticket建立了单向关联关系
通过关联表处理单向关联:
通过联接表处理单向一对多关联是首选方式,这种关联通过@JoinTable批注进行描述
@Entity
Public class Trainer{
@OneToMany
@JoinTable(
   name = "TrainedMonkeys",
   jonColumns = {@JoinColumn(name = "trainer_id")},
   inverseJoinColumns = @JoinColumn(name = "monkey_id")
   )
public Set<Monkey> getTrainedMonkeys() {
      return trainedMonkeys;
   }
......
}
@Entity
public class Monkey {
...//no bidir
}
上面这个例子中,Trainer通过TrainedMonkeys表和Monkey建立了单向关联,其中外键trainer_id关联到Trainer(joinColoumn),而外键monkey_id关联到Monkey(inversejionColoumns)
默认处理机制:
通过联接表来建立单向一对多关联不需要描述任何物理映像,表名由以下三个部分组成:主表(ownertable)表名+从表(the other side table)表名,指向主表的外键名:主表表名+下划线+主表主键列名,指向从表的外键名:主表所对应实体的属性名+下划线+从表主键列名,指向从表的外键定义为唯一约束,用来表示一对多的关联关系。
@Entity
public class Trainer{
   @OneToMany
   Public Set<Tiger> getTrainedTigers(){
... ...
}
@Entity
public class Tiger{
.. ..//no bidir
}
上面这个例子中,Trainer和Tiger通过联接表Trainer_Tiger建立单向关联关系,其中外键trainer_id关联到Trainer,而外键trainedTigers_id关联到Tiger
 
多对多(Many-to-Many)
使用@ManyToMany批注可定义多对多关联,同时,你也许要通过批注@JoinTable描述关联表和关联条件。如果是双向关联,其中一段必须定义为Owner,另一端必须定义为inverse(在对关联表进行更新操作时这一端将被忽略)
@Entity()
public class Employer implements Serializable {
   private Integer id;
   private Collection employees;
   @ManyToMany(
targetEntity = org.hibernate.test.annotations.manytomany.Employee.class,
      cascade = {CascadeType.PERSIST, CascadeType.MERGE}
   )
   @JoinTable(
         name = "EMPLOYER_EMPLOYEE",
         joinColumns = {@JoinColumn(name = "EMPER_ID")},
         inverseJoinColumns = {@JoinColumn(name = "EMPEE_ID")}
   )
   public Collection getEmployees() {
      return employees;
   }
...
}
@Entity()
public class Employee implements Serializable {
   @ManyToMany(
         cascade = {CascadeType.PERSIST, CascadeType.MERGE},
         mappedBy = "employees"
         targetEntity = Employer.class
   )
public Collection<Employer> getEmployers() {
      return employers;
   }
.. ..
}
@JoinTable批注定义了联接表的表名,联接列数组,以及invers联接列数组,后者是关联表中关联到Employee主键的列(the “other side”)。
被关联端不必也不能描述物理映射:只需要一个简单的mappedBy参数,该参数包含了主体端的属性名,这样就绑定了双方的关系。
默认值:
和其它许多批注一样,在多对多关联中很多值是自动生成,党双向多对多关联中没有定义任何物理映射时,Hibernate根据以下规则生成相应的值,关联表名:主表表名+下划线+从表表名,关联到主表的外键名:主表名+下划线+主表中的主键列名,关联到从表的外键名:主表中用于关联的属性名+下划线+从表的主键列名,以上规则对于双向一对多关联同样一样。
 
以上是整理的一点简单的几种映射,可参考EJB3.pdf中P111——P131,hibernate_annotation.pdf 第二章
在这里没有具体的例子,有很多内容还需要仔细查看文档。
posted on 2011-12-20 14:10 紫蝶∏飛揚↗ 阅读(1110) 评论(0)  编辑  收藏 所属分类: Hibernate数据库

只有注册用户登录后才能发表评论。


网站导航: