在Hibarbate如果你想实现权限表的话,我们可以使用一对多的自关联关系来实现:
首先实体类:
public class TreeNode {
private Integer nodeId;
private String nodeName;
private Integer treeNodeType;
private Integer position;
private String url;
private TreeNode parent;
private Set<TreeNode> children = new HashSet<TreeNode>();
private Integer initChildren = 0;
}
提供set/get方法,
这里可以看到 Set TreeNode children 这里面放的是自己,
所以他是自关联关系。
在xml里的配置如下:
<hibernate-mapping>
<class name="com.zlk.four.entity.TreeNode" table="t_hibernate_sys_tree_node">
<id name="nodeId" type="java.lang.Integer" column="tree_node_id">
<generator class="increment" />
</id>
<property name="nodeName" type="java.lang.String"
column="tree_node_name">
</property>
<property name="treeNodeType" type="java.lang.Integer"
column="tree_node_type">
</property>
<property name="position" type="java.lang.Integer"
column="position">
</property>
<property name="url" type="java.lang.String"
column="url">
</property>
<many-to-one name="parent" class="com.zlk.four.entity.TreeNode" column="parent_node_id"/>
<set name="children" cascade="save-update" inverse="true">
<key column="parent_node_id"></key>
<one-to-many class="com.zlk.four.entity.TreeNode"/>
</set>
</class>
</hibernate-mapping>
因为是自关联,所以两个配置都写在一个xml里面,
方法:
public class TreeNodeDao {
public TreeNode load(TreeNode treeNode) {
Session session = SessionFactoryUtils.openSession();
Transaction transaction = session.beginTransaction();
TreeNode t = session.load(TreeNode.class, treeNode.getNodeId());
if(t != null && new Integer(1).equals(treeNode.getInitChildren())) {
Hibernate.initialize(t.getChildren());
Hibernate.initialize(t.getParent());
}
transaction.commit();
session.close();
return t;
}
上篇博客中提到过,initChildren是用来控制是否强加载的,因为权限表,即有子节点也有父节点,当你查找的时候会很耗性能,会把所有资源全加载出来,但你可能只需要一个表的资源,所以用到initChildren来控制,但这样也有个坏处,那就是如果你的表中有更多个的话,if判断语句会有更多,这样就造成代码臃肿。
那有什么方法可以解决呢?
这里可以运用Hibarnate的其他关联关系:多地对多。
在这里我运用二星权限表来演示一下,
实体类 :
public class Book{
private Integer bookId;
private String bookName;
private Float price;
private Set<Category> categories = new HashSet<Category>();
private Integer initCategories = 0;
// set/get
}
public class Category{
private Integer categoryId;
private String categoryName;
private Set<Book> books = new HashSet<Book>();
// set/get
}
书可以有多个类型,而每个类型可以有多本书,即多对多。
二星权限中第有一个中间表,但这个中间表在这里是可以不实例化的。交给这两个表来维护即可。
但是还是要数据库表的,两条列即可,bookId 和 categoryId 。进行相对应。
book xml配置:
<!--
table:代表的是中间表
name:书籍类的关联属性
inverse:中间表交于对方维护
key:当前类的主键在中间表对应的列段
many-to-many:
column:关联表的主键在中间表的列段
class:中间表的实体类
-->
<set table="t_hibernate_book_category" name="categories" cascade="save-update" inverse="false">
<!-- one -->
<key column="bid"></key>
<!-- many -->
<many-to-many column="cid" class="com.zlk.four.entity.Category"></many-to-many>
</set>
category xml配置 :
<set table="t_hibernate_book_category" name="books" cascade="save-update" inverse="false">
<key column="cid"></key>
<many-to-many column="bid" class="com.zlk.four.entity.Book"></many-to-many>
</set>
其实两个配置是一样的,因为是多对多。
之所以 categories 和 books里面有值就是通过这个set获得值的,
顺序是:
首先获得书的id然后通过key获得中间表中的对应的cid,再通过cid获得类型表,即通过cid得到类型的集合,即获得成功。
在这里要注意的是inverse=“false”,这个的意思就是交由谁来维护。
测试:
/**
* book.hbm.xml inverse=fasle
* category.hbm.xml inverse=true
* 数据添加正常
* 书籍表、桥接表各新增一条数据
*/
@Test
public void test1() {
Book book = new Book();
book.setBookName("b");
book.setPrice(10f);
Category category = new Category();
category.setCategoryId(5);
// 直接将category对象加入到新建的book中是错误的,因为此时的category是临时态的,hibernate是不会管理的
// book.getCategories().add(category);
Category c = this.bookDao.getCategory(category);
// c.getBooks().add(book);
book.getCategories().add(c);
this.bookDao.addBook(book);
}
两个数据表中都增加了数据进去。即成功