(十二)Hibernate中的多表操作(2):单向多对一
- 由“多”方可知“一”方的信息,比如多个员工使用同一栋公寓,员工可以知道公寓的信息,而公寓无法知道员工的信息。
案例一:使用xml配置
- pojo类 Group.java
package bean; // default package /** * Group entity. @author MyEclipse Persistence Tools */ public class Group implements java.io.Serializable { // Fields private Integer groupid; private String groupname; //省略get和set方法 //省略空的和满的构造方法 }
GroupUser.java
package bean; // default package /** * GroupUser entity. @author MyEclipse Persistence Tools */ public class GroupUser implements java.io.Serializable { // Fields private Integer userid; private String username; private Group group; //省略get和set方法 //省略构造方法 }
- 实体映射文件 Group.hbm.xml
<?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="bean.Group" table="t_group" catalog="test"> <id name="groupid" type="java.lang.Integer"> <column name="groupid" /> <generator class="assigned"></generator> </id> <property name="groupname" type="java.lang.String"> <column name="groupname" /> </property> </class> </hibernate-mapping>
GroupUser.hbm.xml
<?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"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="bean.GroupUser" table="t_groupuser" catalog="test"> <id name="userid" type="java.lang.Integer"> <column name="userid" /> <generator class="assigned"></generator> </id> <property name="username" type="java.lang.String"> <column name="username" /> </property> <!-- name的值要与本类的属性名一致,这里指定这个bean映射的表的外键为group_id属性且该属性是自动生成的,所以必须与数据库中的外键字段一致,
//所以该bean就不需要设置表中外键的映射了。 // hibernate默认该外键关联group映射的表的主键, --> <many-to-one name="group" class="bean.Group" column="group_id" cascade="all"></many-to-one> <!-- class值指定了“一”方的类 --> </class> </hibernate-mapping>
-
<many-to-one >元素建立了department属性和employee表的外键depart_id之间的映射.
<many-to-one name="group" class="bean.Group" column="group_id" cascade="all">
- <many-to-one name="group" class="bean.Group" column="group_id" cascade="all">这种情况,hibernate会默认去group对象中查找主键值,因为hibernate默认的是外键对应另一个表中的主键的,如果想对应group中的其它属性,如”name”,则可以使用<many-to-one name=”group” column=”group_id” property-ref=”name”/>
-
name: 设定待映射的持久化类的属性名,此外为employee类的department属性.
column: 设定和持久化类的属性对应的表的外键,此外为employee表的外键depart_id.
class(可选):设定持久化类的属性的类型,此处设定department的类型是Department类.
not-null(可选):如果为true,表示department属性不能为null,该属性的默认值为false.当为true时,生成的employee表中depart_id外键会设置not-null约束,所以当Hibernate保存Employee对象时,会先检查它的department属性是否为null,如果为null,则会抛出异常.
案例二:使用注解配置
- 多个用户对应一个组,一个组有多个用户。且多个用户可以知道组的信息,但是组不能知道用户的信息。
- 数据库中表结构:
- 建议pojo持久化类: Group.java
package bean; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; @Entity @Table(name = "t_group") public class Group implements Serializable { @Id @GeneratedValue(generator="a") @GenericGenerator(name="a",strategy="assigned") private Integer groupid;
@Column(name="groupname") private String groupName; //省略get和set方法 //省略空的构造方法和满构造方法 }
- GroupUser.java
package bean; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; @Entity @Table(name = "t_groupuser") public class GroupUser implements Serializable { @Id @GeneratedValue(generator = "designed") @GenericGenerator(name = "designed", strategy = "assigned") private Integer userid; private String username; @ManyToOne(cascade = { CascadeType.REMOVE, CascadeType.MERGE }) // 设置关联关系和级联类型 @JoinColumn(name = "group_id") // 该注解表示指定外键,这里指定这个bean映射的表的外键为group_id属性且该属性是自动生成的,所以必须与数据库中的外键字段一致,所以该bean就不需要设置表中外键的映射了。
// hibernate默认该外键关联group映射的表的主键, private Group group; public GroupUser() { } public GroupUser(Integer userid, String username) { super(); this.userid = userid; this.username = username; } public Integer getUserid() { return userid; } public void setUserid(Integer userid) { this.userid = userid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } }
- 测试类 Test_ManytoOne.java
package action; import org.hibernate.Session; import org.hibernate.Transaction; import bean.Group; import bean.GroupUser; import util.HibernateUtil; /** * 本类测试多对一的操作 * @author 半颗柠檬、 * */ public class Test_ManytoOne { public static void main(String[] args) { Test_ManytoOne.save(); // Test_ManytoOne.select(); // Test_ManytoOne.delete(); } public static void save(){ Session session = null; Transaction tran = null; try { session = HibernateUtil.getSessionFactory().getCurrentSession(); tran=session.beginTransaction(); //添加一个组 Group group=new Group(); group.setGid(1); group.setGroupName("管理员组"); //添加组成员 GroupUser user=new GroupUser(); user.setUserid(1); user.setUsername("admin1"); user.setGroup(group); GroupUser user1=new GroupUser(); user1.setUserid(2); user1.setUsername("admin2"); user1.setGroup(group); session.save(group); session.save(user); session.save(user1); tran.commit(); } catch (Exception e) { e.printStackTrace(); tran.rollback(); } } /** * 测试单向对一是否只能多方读取一方,而一方不能读取多方 */ private static void select() { Session session = null; Transaction tran = null; try { session = HibernateUtil.getSessionFactory().getCurrentSession(); tran=session.beginTransaction(); GroupUser user= (GroupUser)session.get(GroupUser.class, new Integer(2)); System.out.println(user.getUserid()+"\t"+user.getUsername()); //单向获取“一”方的信息 Group group=user.getGroup(); System.out.println("groupid="+group.getGid()+"\t"+group.getGroupName()); tran.commit(); } catch (Exception e) { e.printStackTrace(); tran.rollback(); } } /** * 删除Many一方时,默认不会级联删除One的一方。 * * 如果要级联删除:,一般使用代码手动级联更新 * * A:使用代码来控制级联删除。[使用这种方式] * * B:配置级联关系,让Hibernate自动执行。 * * 在关联关系中配置cascade属性。 * * @ManyToOne(cascade = { CascadeType.REMOVE, CascadeType.MERGE }) * */ private static void delete() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); /** * A:使用代码控制级联 */ // GroupUser user = (GroupUser) session.get(GroupUser.class, // new Integer(1)); // // session.delete(user); // // Group group = user.getGroup(); // session.delete(group); /** * B 在关联关系中配置cascade属性之后 */ GroupUser user = (GroupUser) session.get(GroupUser.class, new Integer(1)); session.delete(user); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(); } } }
- 一对多可以从“一”方得到“多”方的信息,那么可以用
OneToMany
@JoinColumn(name = " ")
@OrderBy(value=" studentID desc")
来对获得的“多”方信息进行排序