Hibernate 自关联注解方式 Hibernate自关联(使用注解)

今天下午搞了个使用注解的自连接一对多,以前用的都是配置文件,突然间用注解,一下子没找到方向,所以记录下来。

主要是现实一个多级菜单。

表结构:

Sql代码   收藏代码
  1. create table SMS_MENU  
  2. (  
  3.   ID     NUMBER not null--pk  
  4.   NAME   VARCHAR2(255), --菜单名  
  5.   LINK   VARCHAR2(255),--菜单链接  
  6.   GRADE  NUMBER,--菜单等级  
  7.   PID    NUMBER,  --fk reference SMS_MENU(ID) 父菜单id  
  8.   MORDER NUMBER --同一级菜单的菜单顺序  
  9. )  

 节约点地方,有些没用的getter setter 就不写了。

entity:

 

Java代码   收藏代码
  1. /** 
  2.  * 用户的菜单 
  3.  * @author kenshin 
  4.  * 
  5.  */  
  6. @Entity  
  7. @Table(name = "SMS_MENU")  
  8. @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)  
  9. public class Menu extends IdEntity {  
  10.   
  11.     private String name;  
  12.     private String link;  
  13.     private Integer grade; //菜单等级  
  14.     private Integer morder; //同一级菜单中的顺序  
  15.   
  16.     private Menu parentMenu;  
  17.     //子菜单列表  
  18.     private List<Menu> childMenu = new ArrayList<Menu>();  
  19.   
  20.     public Menu() {  
  21.         super();  
  22.     }  
  23.   
  24.     @Column(nullable = false, unique = true)  
  25.     public String getName() {  
  26.         return name;  
  27.     }  
  28.   
  29.     @ManyToOne(fetch = FetchType.LAZY)  
  30.     @JoinColumn(name = "pid")  
  31.     public Menu getParentMenu() {  
  32.         return parentMenu;  
  33.     }  
  34.   
  35.     @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")  
  36.     @Fetch(FetchMode.SUBSELECT)  
  37.     @OrderBy("morder")  
  38.     public List<Menu> getChildMenu() {  
  39.         return childMenu;  
  40.     }  
  41.   
  42. }  

 其实不同表的一对多,和自连接的一对多是一样的,只不过突然变成一张表,多方和一方都在一起,我的笨脑子突然没反应过来,所以折腾了多好久。

一个父菜单对应多个子菜单

先把Menu作为”一”的一方看(当做父菜单)

其实它应该有的属性是childMenu这个集合

所以在getChildMenu()方法上有如下如下注解

Java代码   收藏代码
  1. @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")  
  2. @Fetch(FetchMode.SUBSELECT)  
  3. @OrderBy("morder")  

OneToMany自然表示一对多

targetEntity 的参数, 该参数定义了目标实体名.通常不需要定义该参数, 因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足要求了.

也就是说hibernate能通过属性的类型来决定这个值,所以设不设该值问题不大。

cascade表示级联风格,ALL=save-update,delete

最主要的就是mappedBy,我一开始狂找inverse这个属性在哪里设置,就是没找到。

原来在注解的设置中,是使用mappedBy来定义由谁来维护外键的。

在一对多的时候,多的一方是关系维护端,一的一方是关系被维护端。在关系被维护端里面有mappedBy 关系维护方对应的表中应该有外键

在本例中,父菜单所表示的Menu为关系被维护方,所以要在集合上声明mappedBy,表示外键由哪一方维护。

不设置的默认情况下,外键是由一的一方维护的,

Java代码   收藏代码
  1. Menu dsd = entityDao.get(333L);  
  2. Menu m3 = new Menu("A管理""**"13);  
  3. Menu m4 = new Menu("B管理""**"14);  
  4. dsd.addChild(m3);  
  5. dsd.addChild(m4);  
  6. entityDao.save(dsd);  
  7. flush();  
 

如果你调试以上方法,你会发现每一条insert语句后,都会再多一句update语句,虽然在insert语句中已经把pid记录到数据库,但是由于一的一方要维护外键,所以又多了2条update的sql

Sql代码   收藏代码
  1. Hibernate:   
  2.     insert   
  3.     into  
  4.         sms_menu  
  5.         (grade, link, morder, name, pid, id)   
  6.     values  
  7.         (?, ?, ?, ?, ?, ?)  
  8. Hibernate:   
  9.     insert   
  10.     into  
  11.         sms_menu  
  12.         (grade, link, morder, name, pid, id)   
  13.     values  
  14.         (?, ?, ?, ?, ?, ?)  
  15. Hibernate:   
  16.     update  
  17.         sms_menu   
  18.     set  
  19.         pid=?   
  20.     where  
  21.         id=?  
  22. Hibernate:   
  23.     update  
  24.         sms_menu   
  25.     set  
  26.         pid=?   
  27.     where  
  28.         id=?  

 这个非常影响性能

所以必须加上mappedBy="parentMenu"

这句话表示由多的一方自己来维护外键

在多的一方,也就是子菜单对应的Menu,中应该会有一个属性parentMenu指定他的父菜单对象,同时对应的表中的外键列,即PID

这样设置后,调试的结果就只剩下2句insert的sql

Sql代码   收藏代码
  1. Hibernate:   
  2.     insert   
  3.     into  
  4.         sms_menu  
  5.         (grade, link, morder, name, pid, id)   
  6.     values  
  7.         (?, ?, ?, ?, ?, ?)  
  8. Hibernate:   
  9.     insert   
  10.     into  
  11.         sms_menu  
  12.         (grade, link, morder, name, pid, id)   
  13.     values  
  14.         (?, ?, ?, ?, ?, ?)  

 现在自关联就是把父菜单对应的Menu,和子菜单对应的Menu合并成一个对象,

好了自关联的Hibernate注解设置完成了。

今天下午搞了个使用注解的自连接一对多,以前用的都是配置文件,突然间用注解,一下子没找到方向,所以记录下来。

主要是现实一个多级菜单。

表结构:

Sql代码   收藏代码
  1. create table SMS_MENU  
  2. (  
  3.   ID     NUMBER not null--pk  
  4.   NAME   VARCHAR2(255), --菜单名  
  5.   LINK   VARCHAR2(255),--菜单链接  
  6.   GRADE  NUMBER,--菜单等级  
  7.   PID    NUMBER,  --fk reference SMS_MENU(ID) 父菜单id  
  8.   MORDER NUMBER --同一级菜单的菜单顺序  
  9. )  

 节约点地方,有些没用的getter setter 就不写了。

entity:

 

Java代码   收藏代码
  1. /** 
  2.  * 用户的菜单 
  3.  * @author kenshin 
  4.  * 
  5.  */  
  6. @Entity  
  7. @Table(name = "SMS_MENU")  
  8. @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)  
  9. public class Menu extends IdEntity {  
  10.   
  11.     private String name;  
  12.     private String link;  
  13.     private Integer grade; //菜单等级  
  14.     private Integer morder; //同一级菜单中的顺序  
  15.   
  16.     private Menu parentMenu;  
  17.     //子菜单列表  
  18.     private List<Menu> childMenu = new ArrayList<Menu>();  
  19.   
  20.     public Menu() {  
  21.         super();  
  22.     }  
  23.   
  24.     @Column(nullable = false, unique = true)  
  25.     public String getName() {  
  26.         return name;  
  27.     }  
  28.   
  29.     @ManyToOne(fetch = FetchType.LAZY)  
  30.     @JoinColumn(name = "pid")  
  31.     public Menu getParentMenu() {  
  32.         return parentMenu;  
  33.     }  
  34.   
  35.     @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")  
  36.     @Fetch(FetchMode.SUBSELECT)  
  37.     @OrderBy("morder")  
  38.     public List<Menu> getChildMenu() {  
  39.         return childMenu;  
  40.     }  
  41.   
  42. }  

 其实不同表的一对多,和自连接的一对多是一样的,只不过突然变成一张表,多方和一方都在一起,我的笨脑子突然没反应过来,所以折腾了多好久。

一个父菜单对应多个子菜单

先把Menu作为”一”的一方看(当做父菜单)

其实它应该有的属性是childMenu这个集合

所以在getChildMenu()方法上有如下如下注解

Java代码   收藏代码
  1. @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")  
  2. @Fetch(FetchMode.SUBSELECT)  
  3. @OrderBy("morder")  

OneToMany自然表示一对多

targetEntity 的参数, 该参数定义了目标实体名.通常不需要定义该参数, 因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足要求了.

也就是说hibernate能通过属性的类型来决定这个值,所以设不设该值问题不大。

cascade表示级联风格,ALL=save-update,delete

最主要的就是mappedBy,我一开始狂找inverse这个属性在哪里设置,就是没找到。

原来在注解的设置中,是使用mappedBy来定义由谁来维护外键的。

在一对多的时候,多的一方是关系维护端,一的一方是关系被维护端。在关系被维护端里面有mappedBy 关系维护方对应的表中应该有外键

在本例中,父菜单所表示的Menu为关系被维护方,所以要在集合上声明mappedBy,表示外键由哪一方维护。

不设置的默认情况下,外键是由一的一方维护的,

Java代码   收藏代码
  1. Menu dsd = entityDao.get(333L);  
  2. Menu m3 = new Menu("A管理""**"13);  
  3. Menu m4 = new Menu("B管理""**"14);  
  4. dsd.addChild(m3);  
  5. dsd.addChild(m4);  
  6. entityDao.save(dsd);  
  7. flush();  
 

如果你调试以上方法,你会发现每一条insert语句后,都会再多一句update语句,虽然在insert语句中已经把pid记录到数据库,但是由于一的一方要维护外键,所以又多了2条update的sql

Sql代码   收藏代码
  1. Hibernate:   
  2.     insert   
  3.     into  
  4.         sms_menu  
  5.         (grade, link, morder, name, pid, id)   
  6.     values  
  7.         (?, ?, ?, ?, ?, ?)  
  8. Hibernate:   
  9.     insert   
  10.     into  
  11.         sms_menu  
  12.         (grade, link, morder, name, pid, id)   
  13.     values  
  14.         (?, ?, ?, ?, ?, ?)  
  15. Hibernate:   
  16.     update  
  17.         sms_menu   
  18.     set  
  19.         pid=?   
  20.     where  
  21.         id=?  
  22. Hibernate:   
  23.     update  
  24.         sms_menu   
  25.     set  
  26.         pid=?   
  27.     where  
  28.         id=?  

 这个非常影响性能

所以必须加上mappedBy="parentMenu"

这句话表示由多的一方自己来维护外键

在多的一方,也就是子菜单对应的Menu,中应该会有一个属性parentMenu指定他的父菜单对象,同时对应的表中的外键列,即PID

这样设置后,调试的结果就只剩下2句insert的sql

Sql代码   收藏代码
  1. Hibernate:   
  2.     insert   
  3.     into  
  4.         sms_menu  
  5.         (grade, link, morder, name, pid, id)   
  6.     values  
  7.         (?, ?, ?, ?, ?, ?)  
  8. Hibernate:   
  9.     insert   
  10.     into  
  11.         sms_menu  
  12.         (grade, link, morder, name, pid, id)   
  13.     values  
  14.         (?, ?, ?, ?, ?, ?)  

 现在自关联就是把父菜单对应的Menu,和子菜单对应的Menu合并成一个对象,

好了自关联的Hibernate注解设置完成了。

猜你喜欢

转载自guobin6125.iteye.com/blog/1597937