Hibernate many-to-many,many-to-one,inverse测试

来源:互联网 发布:php禁止某地区ip 编辑:程序博客网 时间:2024/05/23 12:23

近日工作中发现对Hibernate一些概念模糊.故望此文可以帮助我理顺思路.
写了一个简单的Demo做测试.

两个实体

public class Type {        private int id;        private String name;        private Set books;        //省略getter,setter等方法,下同}public class Book implements Serializable {        private int id;        private String name;        private String desc;        private String price;        private Date createTime;        private Date updateTime;        private Type type;        private Set orders;}public class Order {        private int id;        private Date createTime;        private Set books;}

 

 

关系映射文件

 

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>    <class name="hadix.demo.hibernate.model.Book" table="book">        <id name="id">            <column name="id" sql-type="integer" length="2000000000" precision="10"                    not-null="true"/>            <generator class="increment"/>        </id>        <property name="name">            <column name="name" sql-type="varchar(500)" length="2000000000" precision="10"/>        </property>        <property name="desc">            <column name="desc" sql-type="text" length="2000000000" precision="10"/>        </property>        <property name="price">            <column name="price" sql-type="numeric" length="2000000000" precision="10"/>        </property>        <property name="createTime">            <column name="create_time" sql-type="datetime" length="2000000000" precision="10"/>        </property>        <property name="updateTime">            <column name="update_time" sql-type="datetime" length="2000000000" precision="10"/>        </property>        <many-to-one name="type" column="type_id" class="hadix.demo.hibernate.model.Type"/>        <set name="orders" lazy="true" table="book_order_link" inverse="true">            <key column="book_id"/>            <many-to-many column="order_id" class="hadix.demo.hibernate.model.Order"/>        </set>    </class>    <class name="hadix.demo.hibernate.model.Order" table="order">        <id name="id">            <column name="id" sql-type="integer" length="2000000000" precision="10"                    not-null="true"/>        </id>        <property name="createTime">            <column name="create_time" sql-type="datetime" length="2000000000" precision="10"/>        </property>        <set name="books" table="book_order_link" lazy="false">            <key column="order_id"/>            <many-to-many column="book_id" class="hadix.demo.hibernate.model.Book"/>        </set>    </class>    <class name="hadix.demo.hibernate.model.Type" table="type">        <id name="id">            <column name="id" sql-type="integer" length="2000000000" precision="10"                    not-null="true"/>        </id>        <property name="name">            <column name="name" sql-type="varchar(500)" length="2000000000" precision="10"                    not-null="true" unique="true"/>        </property>        <set name="books" lazy="true" inverse="true">            <key column="type_id"/>            <one-to-many class="hadix.demo.hibernate.model.Book"/>        </set>    </class></hibernate-mapping>

 

 关系图



Book-Order(many-to-many)

Book-Type(many-to-one)

均为双向关系

 

运行测试用例

 

@Testpublic void testManyToOne() {Session session = Sessions.getSession();session.beginTransaction();//持久态 booksList<Book> books = getBooks(session);for (Book book : books) {//数据库中原本已经存放了书籍数据,但未指定类型,所以测试可以通过该断言assertNull(book.getType());}//瞬态 typeType type = new Type("Book_Type_1");type.setBooks(new HashSet<Book>(books));session.saveOrUpdate(type);//type 变为持久态session.getTransaction().commit();session.clear();//清除缓存避免之后取到旧数据//重新读取书籍数据,以确保获得正确关系更新for (Book book : getBooks(session)) {assertEquals(type, book.getType());//期望类型保存后会更新数据库中书跟类型之间的关系}session.close();}private List<Book> getBooks(Session session) {return session.createQuery("from Book").list();}

 结果测试没有通过第二个断言.测试结果是:java.lang.AssertionError:

expected:<Type{id=1, name='Book_Type_1'}> but was:<null>

 

因为在Type一端使用了inverse="true",所以在保存Type对象时并没有保存跟Book间的关系.去掉inverse="true",清除数据库中的type数据,重新执行改测试,则测试通过.

 

接下来的测试验证book和order的多对多关系
@Testpublic void testManyToMany() {Session session = Sessions.getSession();session.beginTransaction();List<Book> books = getBooks(session);HashSet<Book> bookSet = new HashSet<Book>(books);//把同一批书添加到两个订单中Order order1 = newOrder(session, bookSet);Order order2 = newOrder(session, bookSet);session.getTransaction().commit();//验证建立了正确的多对多关系assertEquals(books.size(),order1.getBooks().size());assertEquals(books.size(),order2.getBooks().size());for (Book book : books) {assertEquals(2, book.getOrders().size());}session.close();}private Order newOrder(Session session, HashSet<Book> bookSet) {Order order = new Order();order.setBooks(bookSet);session.save(order);//order对象在保存后变为"持久态"return order;}
 
前面的测试,中注释中标示了一些对象状态转换,下图描述了Hibernate对象状态转换


 
总结
问题:1.Hibernate对象状态转换是隐式的,没经验的用户会比较困惑,在大规模的系统中也很容易出现错误.
2.Hibernate的异常信息是很令人困惑的,写这个demo的过程中,曾出现过一些异常.经检查是由于缺少javassit.jar,但是异常信息却完全与之无关,十分诡异.系统调试经常需要花费很多时间,也未必能找到根本问题.
3.Hibernate的文档描述不明确,inverse和cascade的语义本应十分明确,但是文档描述却不够明确.

我不喜欢这样的工具.作为工具它太复杂了,这种复杂度使学习曲线陡峭,系统调试困难.不适用于我目前的工作.

(第一次写,基本没什么养分..好在让自己重新温习了一下hibernate开发环境配置,明确一下inverse的作用)