单向1:N关系映射

1.无关联表的映射

由于不存在关联表,所以需要在N的一端来存储1的外键。由于N端不负责维护关系,所以N端的映射文件保持不变,仍然为以下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.longtech.hibernate.domain.Department"
        table="Department"> 
        <id name="id" column="id" type="java.lang.Long" >
            <meta attribute="field-description">唯一标识</meta>
            <generator class="native"/>
        </id>
        <property name="name" type="java.lang.String" column="name" length="20">
            <meta attribute="field-description">部门名称</meta>
        </property>
    </class>
</hibernate-mapping>

然后就是1端的映射文件,需要使用one-to-many标签。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.longtech.hibernate.domain.Employee"
        table="Employee"> 
        <id name="id" column="id" type="java.lang.Long" >
            <meta attribute="field-description">唯一标识</meta>
            <generator class="native"/> 
        </id>
        <property name="name" type="java.lang.String" column="name" length="20">
            <meta attribute="field-description">员工名称</meta>
        </property>
        <set name="departments">
            <key column="employid"></key>
            <one-to-many class="com.longtech.hibernate.domain.Department"/>
        </set>
    </class>
</hibernate-mapping>

这个地方为什么不使用many-to-many,然后加上unique=”true”呢?原因是多对多关联必须使用中间表,但是咱们这里是一对多 ,不使用关联表,所以不能使用many-to-many。

下面是储存程序

1,先来个有错误的。

Employee e=new Employee(); 
            e.setName("employ1");
            session.save(e);
            Department dept1=new Department();
            dept1.setName("dept1");
            e.getDepartments().add(dept1);
            Department dept2=new Department();
            dept2.setName("dept2");
            e.getDepartments().add(dept2);
            transaction.commit();

这段代码在储存的时候会抛出异常,为什么呢,因为使用了一个瞬时对象department

但是为什么会是瞬时的呢,因为hibernate在存储的时候是先储存多端,然后再储存1端,最后再用update来更新多端的外键信息。所以当你在insert了employee后,hibernate会去更新department的信息,然后就会找不到相关对象(因为数据库里不存在,如果在数据库里直接执行语句是不会出现更新异常的,但是hibernate会先把数据从数据库中取出来转化为对象再来更新,所以就会出现找不到对象的错误了。

Hibernate: insert into Employee (name) values (?)
Hibernate: update Department set employid=? where id=?
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.longtech.hibernate.domain.Department
    at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:243)

在这里,先储存department,再来存储employee的话就不会有问题了。

通过上面的描述,应该可以看到。这个映射方式的效率是比较低的(因为需要额外的更新语句),并且,外键列上无法增加非空约束。所以来说,这种关系一般会用双向1:N关联。

 

2.有关联表的映射

这种方式和前面的一种差别不大,主要是增加了一个关联表。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.longtech.hibernate.domain.Employee"
        table="Employee"> 
        <id name="id" column="id" type="java.lang.Long" >
            <meta attribute="field-description">唯一标识</meta>
            <generator class="native"/> 
        </id>
        <property name="name" type="java.lang.String" column="name" length="20">
            <meta attribute="field-description">员工名称</meta>
        </property>
        <set name="departments" table="employ_depart">
            <key column="employid"></key>
            <many-to-many class="com.longtech.hibernate.domain.Department" column="deptid" unique="true"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

要使1,2中的程序正常运行,程序代码需要调整为:

Department dept1=new Department();
            dept1.setName("dept1");
            session.save(dept1);
            Department dept2=new Department();
            dept2.setName("dept2");
            session.save(dept2);
            Employee e=new Employee(); 
            e.setName("employ1");
            session.save(e);
            e.getDepartments().add(dept1);
            e.getDepartments().add(dept2);
            transaction.commit();

结束。

posted @ 2012-11-04 09:54  yanglover  阅读(478)  评论(0编辑  收藏  举报