hibernate3.2(六)多对一关联映射
多个用户对应一个组,要在用户中体现出多对一,所以用户中要private Group group
public class User {private int id;//给实体一个唯一性的标识private String name;private Group group; getter and setter...}
?
<?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> <!-- 对类进行映射,name = "完整路径" , 默认存的表和实体类的名字一致, 可以用 table = "xxx"更改生成的数据库表--><class name="com.wyx.hibernate.User" table="t_user"><!-- 标识 数据表默认字段和实体属性名一致,可用column="xxx"来重新定义字段名--><id name="id" column="u_id"> <!-- 主键的生成策略 uuid全局的唯一标识,32位字符串,一般一万年不会重复--> <!-- native 自动根据方言识别 --><generator column="u_name" not-null="true" length="30"/><many-to-one name="group" column="u_group" /></class></hibernate-mapping>
?省略group实体和hbm.xml,注意hbm文件中class标签中要制定table别名,因为默认生成的表group是数据库的关键字,会出错的。
?
执行测试方法:
public void testReference(){Session session = HibernateUtils.getSession();try {session.beginTransaction();Group group = new Group();group.setName("一起探索");User user1 =new User();user1.setName("张三");user1.setGroup(group);User user2 =new User();user2.setName("李四");session.save(group);//不能成功保存session.save(user1);System.out.println("----------mark1------------");session.save(user2);System.out.println("----------mark2------------");//session.save(group);//System.out.println("----------mark3------------");session.getTransaction().commit();} catch (HibernateException e) {e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtils.closeSession(session);}}
?
?这里会报错:
org.hibernate.TransientObjectException.
原因是:
group为transient状态 ,id我们设定为hibernate帮我们自增,id是在session.save方法后,也就是group状态变为persistent才有id,hibernate才给你自动赋值。这里group的id还没有值就被user引用了。去掉注释部分可成功运行。
结论:persistent状态对象是不能引用transient对象,这个错误不注意会经常遇到。
?
那么不存group,有没有办法能不能成功存入user呢?
通过级联操作可以。
级联是对象的连锁操作
级联适合删除、保存、修改。
?
在user.hbm.xml中设置manytoone标签的cascade属性设置为all或save-update,默认是none。
这样在保存person对象的时候,hibernate自动为我们保存group对象,这样person依赖的group数据也就存在了,就可以成功保存内容到数据库。
?
cascade属性设置为除了public void testReferenceLoad(){Session session = HibernateUtils.getSession();try {session.beginTransaction();User user = (User)session.load(User.class, 5);System.out.println("user.name = " + user.getName()+" user.group.name = " + user.getGroup().getName());session.getTransaction().commit();} catch (HibernateException e) {e.printStackTrace();session.getTransaction().rollback();}finally{HibernateUtils.closeSession(session);}}
?Console:
Hibernate: select group0_.g_id as g1_1_0_, group0_.g_name as g2_1_0_ from t_group group0_ where group0_.g_id=?
user.name = 张三 user.group.name = 一起探索
这里不管casecade的值设为任意的都不影响级联查询的进行,因为级联只影响增、删、改的操作。
级联查询真正起作用的是User.hbm.xml中的many-to-one标签。
?
<many-to-one>会在“多”的一方加入外键,指向“一”的一方,这个外键是由该标签下的column属性定义的,即不加column属性默认与“一”的一方的属性名字相同。
?
?