Hibernate 自关联注解方式

本文介绍如何使用Hibernate注解实现自关联一对多关系,包括实体类Menu的属性配置及一对多关系的维护方式。

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

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

表结构:

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注解设置完成了。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值