今天下午搞了个使用注解的自连接一对多,以前用的都是配置文件,突然间用注解,一下子没找到方向,所以记录下来。
主要是现实一个多级菜单。
表结构:
- create table SMS_MENU
- (
- ID NUMBER not null, --pk
- NAME VARCHAR2(255), --菜单名
- LINK VARCHAR2(255),--菜单链接
- GRADE NUMBER,--菜单等级
- PID NUMBER, --fk reference SMS_MENU(ID) 父菜单id
- MORDER NUMBER --同一级菜单的菜单顺序
- )
节约点地方,有些没用的getter setter 就不写了。
entity:
- /**
- * 用户的菜单
- * @author kenshin
- *
- */
- @Entity
- @Table(name = "SMS_MENU")
- @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
- public class Menu extends IdEntity {
- private String name;
- private String link;
- private Integer grade; //菜单等级
- private Integer morder; //同一级菜单中的顺序
- private Menu parentMenu;
- //子菜单列表
- private List<Menu> childMenu = new ArrayList<Menu>();
- public Menu() {
- super();
- }
- @Column(nullable = false, unique = true)
- public String getName() {
- return name;
- }
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "pid")
- public Menu getParentMenu() {
- return parentMenu;
- }
- @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")
- @Fetch(FetchMode.SUBSELECT)
- @OrderBy("morder")
- public List<Menu> getChildMenu() {
- return childMenu;
- }
- }
其实不同表的一对多,和自连接的一对多是一样的,只不过突然变成一张表,多方和一方都在一起,我的笨脑子突然没反应过来,所以折腾了多好久。
一个父菜单对应多个子菜单
先把Menu作为”一”的一方看(当做父菜单)
其实它应该有的属性是childMenu这个集合
所以在getChildMenu()方法上有如下如下注解
- @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")
- @Fetch(FetchMode.SUBSELECT)
- @OrderBy("morder")
OneToMany自然表示一对多
targetEntity 的参数, 该参数定义了目标实体名.通常不需要定义该参数, 因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足要求了.
也就是说hibernate能通过属性的类型来决定这个值,所以设不设该值问题不大。
cascade表示级联风格,ALL=save-update,delete
最主要的就是mappedBy,我一开始狂找inverse这个属性在哪里设置,就是没找到。
原来在注解的设置中,是使用mappedBy来定义由谁来维护外键的。
在一对多的时候,多的一方是关系维护端,一的一方是关系被维护端。在关系被维护端里面有mappedBy 关系维护方对应的表中应该有外键
在本例中,父菜单所表示的Menu为关系被维护方,所以要在集合上声明mappedBy,表示外键由哪一方维护。
不设置的默认情况下,外键是由一的一方维护的,
- Menu dsd = entityDao.get(333L);
- Menu m3 = new Menu("A管理", "**", 1, 3);
- Menu m4 = new Menu("B管理", "**", 1, 4);
- dsd.addChild(m3);
- dsd.addChild(m4);
- entityDao.save(dsd);
- flush();
如果你调试以上方法,你会发现每一条insert语句后,都会再多一句update语句,虽然在insert语句中已经把pid记录到数据库,但是由于一的一方要维护外键,所以又多了2条update的sql
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
- Hibernate:
- update
- sms_menu
- set
- pid=?
- where
- id=?
- Hibernate:
- update
- sms_menu
- set
- pid=?
- where
- id=?
这个非常影响性能
所以必须加上mappedBy="parentMenu"
这句话表示由多的一方自己来维护外键
在多的一方,也就是子菜单对应的Menu,中应该会有一个属性parentMenu指定他的父菜单对象,同时对应的表中的外键列,即PID
这样设置后,调试的结果就只剩下2句insert的sql
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
现在自关联就是把父菜单对应的Menu,和子菜单对应的Menu合并成一个对象,
好了自关联的Hibernate注解设置完成了。
今天下午搞了个使用注解的自连接一对多,以前用的都是配置文件,突然间用注解,一下子没找到方向,所以记录下来。
主要是现实一个多级菜单。
表结构:
- create table SMS_MENU
- (
- ID NUMBER not null, --pk
- NAME VARCHAR2(255), --菜单名
- LINK VARCHAR2(255),--菜单链接
- GRADE NUMBER,--菜单等级
- PID NUMBER, --fk reference SMS_MENU(ID) 父菜单id
- MORDER NUMBER --同一级菜单的菜单顺序
- )
节约点地方,有些没用的getter setter 就不写了。
entity:
- /**
- * 用户的菜单
- * @author kenshin
- *
- */
- @Entity
- @Table(name = "SMS_MENU")
- @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
- public class Menu extends IdEntity {
- private String name;
- private String link;
- private Integer grade; //菜单等级
- private Integer morder; //同一级菜单中的顺序
- private Menu parentMenu;
- //子菜单列表
- private List<Menu> childMenu = new ArrayList<Menu>();
- public Menu() {
- super();
- }
- @Column(nullable = false, unique = true)
- public String getName() {
- return name;
- }
- @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "pid")
- public Menu getParentMenu() {
- return parentMenu;
- }
- @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")
- @Fetch(FetchMode.SUBSELECT)
- @OrderBy("morder")
- public List<Menu> getChildMenu() {
- return childMenu;
- }
- }
其实不同表的一对多,和自连接的一对多是一样的,只不过突然变成一张表,多方和一方都在一起,我的笨脑子突然没反应过来,所以折腾了多好久。
一个父菜单对应多个子菜单
先把Menu作为”一”的一方看(当做父菜单)
其实它应该有的属性是childMenu这个集合
所以在getChildMenu()方法上有如下如下注解
- @OneToMany(targetEntity = Menu.class, cascade = { CascadeType.ALL }, mappedBy = "parentMenu")
- @Fetch(FetchMode.SUBSELECT)
- @OrderBy("morder")
OneToMany自然表示一对多
targetEntity 的参数, 该参数定义了目标实体名.通常不需要定义该参数, 因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足要求了.
也就是说hibernate能通过属性的类型来决定这个值,所以设不设该值问题不大。
cascade表示级联风格,ALL=save-update,delete
最主要的就是mappedBy,我一开始狂找inverse这个属性在哪里设置,就是没找到。
原来在注解的设置中,是使用mappedBy来定义由谁来维护外键的。
在一对多的时候,多的一方是关系维护端,一的一方是关系被维护端。在关系被维护端里面有mappedBy 关系维护方对应的表中应该有外键
在本例中,父菜单所表示的Menu为关系被维护方,所以要在集合上声明mappedBy,表示外键由哪一方维护。
不设置的默认情况下,外键是由一的一方维护的,
- Menu dsd = entityDao.get(333L);
- Menu m3 = new Menu("A管理", "**", 1, 3);
- Menu m4 = new Menu("B管理", "**", 1, 4);
- dsd.addChild(m3);
- dsd.addChild(m4);
- entityDao.save(dsd);
- flush();
如果你调试以上方法,你会发现每一条insert语句后,都会再多一句update语句,虽然在insert语句中已经把pid记录到数据库,但是由于一的一方要维护外键,所以又多了2条update的sql
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
- Hibernate:
- update
- sms_menu
- set
- pid=?
- where
- id=?
- Hibernate:
- update
- sms_menu
- set
- pid=?
- where
- id=?
这个非常影响性能
所以必须加上mappedBy="parentMenu"
这句话表示由多的一方自己来维护外键
在多的一方,也就是子菜单对应的Menu,中应该会有一个属性parentMenu指定他的父菜单对象,同时对应的表中的外键列,即PID
这样设置后,调试的结果就只剩下2句insert的sql
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
- Hibernate:
- insert
- into
- sms_menu
- (grade, link, morder, name, pid, id)
- values
- (?, ?, ?, ?, ?, ?)
现在自关联就是把父菜单对应的Menu,和子菜单对应的Menu合并成一个对象,
好了自关联的Hibernate注解设置完成了。