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 trees;
@onetomany(mappedby="foresttype")
public set gettrees() {// trees的getter,setter方法必须在这里,否则会出错
return trees;
}
public void settrees(set 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 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 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 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 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 getemployers() {
return employers;
}
.. ..
}
@jointable批注定义了联接表的表名,联接列数组,以及invers联接列数组,后者是关联表中关联到employee主键的列(the “other side”)。
被关联端不必也不能描述物理映射:只需要一个简单的mappedby参数,该参数包含了主体端的属性名,这样就绑定了双方的关系。
默认值:
和其它许多批注一样,在多对多关联中很多值是自动生成,党双向多对多关联中没有定义任何物理映射时,hibernate根据以下规则生成相应的值,关联表名:主表表名 下划线 从表表名,关联到主表的外键名:主表名 下划线 主表中的主键列名,关联到从表的外键名:主表中用于关联的属性名 下划线 从表的主键列名,以上规则对于双向一对多关联同样一样。
以上是整理的一点简单的几种映射,可参考ejb3.pdf中p111——p131,hibernate_annotation.pdf 第二章
在这里没有具体的例子,有很多内容还需要仔细查看文档。