Hibernate为程序员提供一种级联操作,在编写程序时,通过Hibernate的级联功能可以很方便的操作数据库的主从表的数据,我们最常用的级联是级联保存和级联删除,下面分别来看一下级联保存和级联删除。
我准备了MenuPanel和Menu两个对象,先来看一下两个对象的关系
从上图可以看出,MenuPanel和Menu是一对多的关系,Menu表同时存在多个子节点,用parentId代表该节点的父节点。
在JPA中,配置级联操作我们可以用cascade=CascadeType.ALL,意思是支持所有的级联操作,网上有很多文章说级联保存用CascadeType.PERSIST,这也是可以的,我们分别在代码中使用以上两个类型。在MenuPane的getChildren()方法中标上下面的注解:
@OneToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY,mappedBy="menu") public List<Menu> getChildren() { return children; }
在Menu的getChildren()的方法中标上下面的注解
@OneToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY,mappedBy="menu") public List<Menu> getChildren() { return children; }
以上代码实现级联保存的配置,我们需要在业务逻辑中为对象设置关系,这样Hibernate才能自动实现级联保存,如果只是配置了级联操作,而没有在对象中设置对象之前的关系,Hibernate是无法实现级联保存的功能的。
首先实例化MenuPanel
MenuPanel panel1 = new MenuPanel("基础设置");
再实例化几个Menu
Menu menuCard=new Menu("会员卡设置",""); menuCard.setLeaf(false); Menu menu1 = new Menu("卡类型设置", "basicOperation/queryCardType"); Menu menu2 = new Menu("站点设定", "basicOperation/querySite"); Menu menu3 = new Menu("操作员授权", "basicOperation/queryOperatorSet"); Menu menu4 = new Menu("密码修改", "test.do"); Menu menu5 = new Menu("消费项目管理", "test1.do");
我们要把menuCard作为menu1的父节点,故作如下设置
List<Menu> cardChildMenus=new ArrayList<Menu>(); cardChildMenus.add(menu1); menuCard.setChildren(cardChildMenus);//把卡类型设置作为会员卡设置的子菜单
设置对象之间的关系,这一步很关键,直接影响保存结果
menu1.setMenu(menuCard);//为会员卡设置设置卡类型设置,以支持级联保存 menuCard.setMenuPanel(panel1); //设置Menu属于MenuPanel menu2.setMenuPanel(panel1); menu3.setMenuPanel(panel1); menu4.setMenuPanel(panel1); menu5.setMenuPanel(panel1); //将Menu添加到MenuPanel panel1.getMenus().add(menuCard); panel1.getMenus().add(menu2); panel1.getMenus().add(menu3); panel1.getMenus().add(menu4); panel1.getMenus().add(menu5);
具体代码:
@Override public boolean testAdd() { List<MenuPanel> menuPanels=new ArrayList<MenuPanel>(); MenuPanel panel1 = new MenuPanel("基础设置"); Menu menuCard=new Menu("会员卡设置",""); menuCard.setLeaf(false); Menu menu1 = new Menu("卡类型设置", "basicOperation/queryCardType"); Menu menu2 = new Menu("站点设定", "basicOperation/querySite"); Menu menu3 = new Menu("操作员授权", "basicOperation/queryOperatorSet"); Menu menu4 = new Menu("密码修改", "test.do"); Menu menu5 = new Menu("消费项目管理", "test1.do"); menu1.setMenu(menuCard);//为会员卡设置设置卡类型设置,以支持级联保存 menuCard.setMenuPanel(panel1); menu2.setMenuPanel(panel1); menu3.setMenuPanel(panel1); menu4.setMenuPanel(panel1); menu5.setMenuPanel(panel1); List<Menu> cardChildMenus=new ArrayList<Menu>(); cardChildMenus.add(menu1); menuCard.setChildren(cardChildMenus);//把卡类型设置作为会员卡设置的子菜单 panel1.getMenus().add(menuCard); panel1.getMenus().add(menu2); panel1.getMenus().add(menu3); panel1.getMenus().add(menu4); panel1.getMenus().add(menu5); MenuPanel panel2 = new MenuPanel("日常操作"); Menu menu10 = new Menu("发行新卡", "operate/cardList?type=add"); Menu menu11 = new Menu("存款入卡", "operate/cardList?type=depositMoney"); Menu menu12 = new Menu("卡中取款", "operate/cardList?type=drawMoney"); Menu menu13 = new Menu("奖品管理", "operate/cardList?type=prize"); Menu menu14 = new Menu("卡挂失", "operate/cardList?type=reportLoss"); Menu menu15 = new Menu("卡解挂", "operate/cardList?type=cancelLoss"); Menu menu16 = new Menu("并卡", "operate/cardList?type=mergeCard"); Menu menu17 = new Menu("补办新卡", "operate/cardList?type=mendCard"); Menu menu18 = new Menu("回收旧卡", "operate/cardList?type=recycleCard"); Menu menu19 = new Menu("维护", "operate/cardList?type=maintain"); menu10.setMenuPanel(panel2); menu11.setMenuPanel(panel2); menu12.setMenuPanel(panel2); menu13.setMenuPanel(panel2); menu14.setMenuPanel(panel2); menu15.setMenuPanel(panel2); menu16.setMenuPanel(panel2); menu17.setMenuPanel(panel2); menu18.setMenuPanel(panel2); menu19.setMenuPanel(panel2); panel2.getMenus().add(menu10); panel2.getMenus().add(menu11); panel2.getMenus().add(menu12); panel2.getMenus().add(menu13); panel2.getMenus().add(menu14); panel2.getMenus().add(menu15); panel2.getMenus().add(menu16); panel2.getMenus().add(menu17); panel2.getMenus().add(menu18); panel2.getMenus().add(menu19); menuPanels=new ArrayList<MenuPanel>(); menuPanels.add(panel1); menuPanels.add(panel2); return menuPanelDao.add(menuPanels); }
执行一下单元测试,看一下效果
@Test public void test() { // menuPanelService.delete(); menuPanelService.testAdd(); } Hibernate: insert into MENUPANEL (text, id) values (?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENUPANEL (text, id) values (?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?) Hibernate: insert into MENU (leaf, parentId, menuPanelId, text, url, id) values (?, ?, ?, ?, ?, ?)
大家可以看到数据全部保存到数据库中了,有图有真像。
图一:MenuPanel表
图二:Menu表
再来看一下级联删除,级联删除可以用CascadeType.REMOVE,先在Menu中的getMenuPanel()方法中加上如下配置,由于我们已经在MenuPanel中配置了cascade=CascadeType.ALL,所以,下面的配置是可以忽略的,之所以这么做,是为了当从Menu中删除对象时能级联删除MenuPanel。
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE}, targetEntity=MenuPanel.class)
在getMenu()方法中也加上如下配置
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE}, targetEntity=Menu.class)
同在要把对象之间的关系解除
menus.get(j).setMenuPanel(null);
具体的代码
@Override public boolean delete() { // TODO Auto-generated method stub Session session = null; try { session =getSession(); Query query = session.createQuery("from MenuPanel"); List<MenuPanel> list = query.list(); for (int i = 0; i < list.size(); i++) { MenuPanel mp = list.get(i); List<Menu> menus = mp.getMenus(); for (int j = 0; j < menus.size(); j++) { menus.get(j).setMenuPanel(null); clareChild(menus.get(j).getChildren()); } super.delete(mp); } return true; } catch (Exception e) { e.printStackTrace(); return false; } finally { // session.close(); } }
执行结果
Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENUPANEL where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENU where id=? Hibernate: delete from MENUPANEL where id=?
POJO类的详细代码如下:
package com.mcs.user.pojo; import java.util.ArrayList; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.OneToMany; import javax.persistence.Table; import com.mcs.pojo.base.GenericObject; /** * 这个是MenuPanel对应的是accordion菜单 * @author lishengbo * */ @Entity @Table(name = "MENUPANEL") public class MenuPanel extends GenericObject { private String text; private List<Menu> menus=new ArrayList<Menu>(); public MenuPanel() { } public MenuPanel(String text) { this.text = text; } public MenuPanel(long id,String text) { this.text = text; super.setId(id+""); } public String getText() { return text; } public void setText(String text) { this.text = text; } /** * 一对多关联Menu菜单,作为Tree中的根节点,这里使用立即加载和MenuPanel一起加载到客户端,注意,一定要使用立即加载 * @return */ @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER,mappedBy="menuPanel") public List<Menu> getMenus() { return menus; } public void setMenus(List<Menu> menus) { this.menus = menus; } } package com.mcs.user.pojo; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; import com.mcs.pojo.base.GenericObject; @Entity @Table(name="MENU") public class Menu extends GenericObject{ private String text; private String url; private boolean leaf=true;//默认是叶子节点 private MenuPanel menuPanel; private List<Menu> children; private Menu menu; public Menu() { } public Menu(String text, String url) { super(); this.text = text; this.url = url; } public Menu(long id,String text, String url,MenuPanel menuPanel) { super(); super.setId(id+""); this.text = text; this.url = url; this.menuPanel=menuPanel; } public String getText() { return text; } public void setText(String text) { this.text = text; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE}, targetEntity=MenuPanel.class) @JoinColumn(name="menuPanelId",referencedColumnName="id",insertable=true,updatable=true) public MenuPanel getMenuPanel() { return menuPanel; } public void setMenuPanel(MenuPanel menuPanel) { this.menuPanel = menuPanel; } @Column(length=1000) public boolean isLeaf() { return leaf; } public void setLeaf(boolean leaf) { this.leaf = leaf; } @OneToMany(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY,mappedBy="menu") public List<Menu> getChildren() { return children; } public void setChildren(List<Menu> children) { this.children = children; } @ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE}, targetEntity=Menu.class) @JoinColumn(name="parentId",referencedColumnName="id",insertable=true,updatable=true) public Menu getMenu() { return menu; } public void setMenu(Menu menu) { this.menu = menu; } }