一. 多对一单向关联映射
多对一关联采用User 和 Group来进行演示
一个User对象属于一个Group,采用单向关联,是User称为主控方,
也即可以通过User对象来获得其所属的Group对象。
User和Group实体的代码如下:
Group.java
package com.tyy.hibernate;
public class Group {
private int id;
private String name;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
|
User.java
package com.tyy.hibernate;
public class User {
private int id;
private String name;
private Group group; //User中包含Group的引用
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Group getGroup() { return group; }
public void setGroup(Group group) { this.group = group; }
}
|
注:为了达到单向关联,其User为主控方的目的,故在User中必须包含Group对象的引用。
如果是双向关联,则也必须在Group中包含User对象的引用。这在下一节中将给于描述。
下一部分主要介绍映射文件的编写,这也是最主要的部分
Group.hbm.xml
<?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 package="com.tyy.hibernate">
<class name="Group" table="t_group"> <id name="id" column="id"> <generator class="native"></generator> </id> <property name="name" column="name"></property>
</class>
</hibernate-mapping> |
User.hbm.xml
<?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 package="com.tyy.hibernate">
<class name="User" table="t_user"> <id name="id" column="id"> <generator class="native"></generator> </id> <property name="name" column="name"></property>
<many-to-one name="group" column="groupid" cascade="save-update"></many-to-one>
</class>
</hibernate-mapping> |
注:Group.hbm.xml与普通的映射文件没有任何区别,对其所有的字段与数据库表都进行了映射,如果没有指定其对应的column属性,则默认与其类属性一直,如果其类属性与数据库中关键字重复,则必须指定其column属性,以改变其在数据库表中对应的字段名
多对一关联会在其主控方中添加一个新的字段,也即会改变其原先的表结构
<many-to-one name="group" column="groupid" cascade="save-update"></many-to-one>
<many-to-one>标签指定了多对一关联的主控方,也即可以得到其相关联对象的实例
name=”group” 与 User.hbm.xml中的 private Group group; 相对应
column=”groupid” 指定了 数据库表中新增加的字段,其字段代表了相关联对象所对应表的主键
mysql> desc t_user; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | groupid | int(11) | YES | MUL | NULL | | +---------+--------------+------+-----+---------+----------------+ 3 rows in set (0.05 sec) |
mysql> desc t_group; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | +-------+--------------+------+-----+---------+----------------+ 2 rows in set (0.02 sec) |
cascade = “save-update” 级联
如果保存或更新当前对象,则其相关联的对象将先执行相应的保存和更新操作
cascade 有一下三种:
none 默认情况下是这样的
delete 在删除的情况下执行
save-update
all 包含所有的,即delete和save-update
测试代码如下:
package com.tyy.hibernate;
import junit.framework.TestCase;
import org.hibernate.Session;
public class ManyToOneTest extends TestCase {
public void testSave1() { Session session = null;
try { session = HibernateUtils.getSessioin(); session.beginTransaction();
Group group = new Group(); group.setName("科大"); // 此处如果不保存gruop,则会出现TransientObjectException异常 // 如果在<many-to-one>标签中设置cascade属性也可以正常保存, // 且会先保存其引用的属性 // session.save(group);
User user1 = new User(); user1.setName("张三"); user1.setGroup(group);
User user2 = new User(); user2.setName("李四"); user2.setGroup(group);
session.save(user1); session.save(user2);
session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); }
}
} |
如果不配置级联,则在保存user1 和 user2之前,应该先保存group对象。
否则会抛出TransientObjectException异常
二. 一对多关联(双向))(参照d:/workspace/hibernate/user_article_one2many项目)
说明:论坛系统中的用户和已发帖子之间的一对多双向关联
用户可以查看自己发的所有帖子,而通过帖子也可以看到是由哪个用户发的。
当添加一个帖子时,也相应的增加一条该用户的信息。此处并没有在t_user表中添加一个表示发表帖子数量的属性,而是继续向t_user表中添加一条发帖人的记录,该记录的username可以重复. 所以应该在Article端设置cascade=”save-updae”
当删除一个用户时,其所发表的所有帖子不会消失;删除一个帖子时,其发帖人也不会被删除。
测试过程:
1. 编写Hibernate配置文件hibernte.cfg.xml,放在/src目录下
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration> <session-factory> <property name="hibernate.connection.url"> jdbc:mysql://localhost/user_article_one2many </property> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">passwd</property> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="hibernate.show_sql">true</property> <!-- <property name="hibernate.hbm2ddl.auto">update</property> -->
<mapping resource="com/tyy/pojo/Article.hbm.xml"/> <mapping resource="com/tyy/pojo/User.hbm.xml"/>
</session-factory> </hibernate-configuration> |
2. 定义两个实体类,并且放在com.tyy.pojo包中
User.java
package com.tyy.pojo;
import java.util.Set;
public class User {
private int id;
// private String userid;
private String username;
private String password;
private Set<Article> articles;
// setter and getter method………
|
Article.java
package com.tyy.pojo;
public class Article {
private int id;
private String title;
private String content;
private User user;
// setter and getter method………
|
3. 定义实体映射文件User.hbm.xml和Article.hbm.xml,也放在com.tyy.pojo包中
User.hbm.xml
<?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 package="com.tyy.pojo">
<class name="User" table="t_user">
<id name="id"> <generator class="native" /> </id>
<property name="username"></property> <property name="password"></property> <set name="articles" inverse="true" table="t_article" > <key column="userid"></key> <one-to-many class="Article" /> </set>
</class>
</hibernate-mapping> |
Article.hbm.xml
<?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 package="com.tyy.pojo">
<class name="Article" table="t_article"> <id name="id"> <generator class="native" /> </id> <property name="title"></property> <property name="content"></property>
<many-to-one name="user" column="userid" class="User" cascade="all" not-null="true"></many-to-one> </class>
</hibernate-mapping> |
4. 将User.hbm.xml和Article.hbm.xml添加到hibernte.cfg.xml中
<mapping resource="com/tyy/pojo/Article.hbm.xml"/> <mapping resource="com/tyy/pojo/User.hbm.xml"/> |
5. 编写hbm2ddl工具类,将实体类生成数据库。放入com.tyy.util包中
DBExport.java
package com.tyy.util;
import org.hibernate.cfg.Configuration; import org.hibernate.tool.hbm2ddl.SchemaExport;
public class DBExport {
public static void main(String[] args) {
Configuration config = new Configuration().configure();
SchemaExport export = new SchemaExport(config);
export.create(true, true);
}
}
|
6. 编写一个用于打开Session和关闭Session的工具类,放入com.tyy.util包中
HibernteUtils.java
package com.tyy.util;
import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory factory;
static { Configuration config = new Configuration().configure(); factory = config.buildSessionFactory(); }
public static Session getSession() { Session session = null; try { session = factory.openSession(); } catch (Exception e) { e.printStackTrace(); } return session; }
public static void closeSession(Session session) { if (session != null) { if (session.isOpen()) { session.close(); } } }
} |
7. 编写测试类
新建一个source folder,名为test,用于测试,在其下建一个包为com.tyy.pojo。
One2ManyTest.java
package com.tyy.pojo;
import java.util.HashSet; import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
import com.tyy.util.HibernateUtils;
public class One2ManyTest extends TestCase {
/** * 当发表帖子时,会将帖子保存到t_article中,同时也自动将其发帖人也保存到t_user表中 */ public void testSave() { Session session = null; System.out.println("before of try"); try { session = HibernateUtils.getSession();
session.beginTransaction();
User user = new User(); user.setUsername("root"); user.setPassword("passwd");
Article article1 = new Article(); article1.setTitle("留言标题"); article1.setContent("留言内容");
// user.getArticles().add(article1);
article1.setUser(user);
Article article2 = new Article(); article2.setTitle("留言标题2"); article2.setContent("留言内容2");
article2.setUser(user);
Set<Article> articles = new HashSet<Article>(); articles.add(article1); articles.add(article2); user.setArticles(articles);
// Set<Article> articles = new HashSet<Article>(); // // articles.add(article1); // articles.add(article2);
// user.setArticles(articles);
// session.save(user); session.save(article1); session.save(article2);
// session.save(user);
session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } }
public void testSave2() { Session session = null; try { session = HibernateUtils.getSession(); session.beginTransaction();
Article article = new Article(); article.setTitle("帖子标题3"); article.setContent("帖子内容3");
User user = new User(); user.setUsername("scott"); user.setPassword("tiger");
Set<Article> articles = new HashSet<Article>(); articles.add(article); user.setArticles(articles);
article.setUser(user);
session.save(article);
session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { HibernateUtils.closeSession(session); } } } |