Hibernate笔记2--映射对象之间的关系

来源:互联网 发布:知乎专栏怎么写文章 编辑:程序博客网 时间:2024/04/30 21:22

 今天心情好。。建了一个比笔记1那篇更简单的表来演示Foo程序:)

 

一。数据库格式

user表

address表

address表持有user_id外键,由此应该可以看出两张表表示的关系为: “1个用户可以拥有多个地址”

 

二。双向关联

下面生成POJO对象:

  1. package model;
  2. /**
  3.  * Address entity.
  4.  * 
  5.  * @author MyEclipse Persistence Tools
  6.  */
  7. public class Address implements java.io.Serializable {
  8.     // Fields
  9.     private Integer addressId;
  10.     private User user;
  11.     private String addressDetail;
  12.     // Constructors
  13.     /** default constructor */
  14.     public Address() {
  15.     }
  16.     /** minimal constructor */
  17.     public Address(User user) {
  18.         this.user = user;
  19.     }
  20.     /** full constructor */
  21.     public Address(User user, String addressDetail) {
  22.         this.user = user;
  23.         this.addressDetail = addressDetail;
  24.     }
  25.     // Property accessors
  26.     public Integer getAddressId() {
  27.         return this.addressId;
  28.     }
  29.     public void setAddressId(Integer addressId) {
  30.         this.addressId = addressId;
  31.     }
  32.     public User getUser() {
  33.         return this.user;
  34.     }
  35.     public void setUser(User user) {
  36.         this.user = user;
  37.     }
  38.     public String getAddressDetail() {
  39.         return this.addressDetail;
  40.     }
  41.     public void setAddressDetail(String addressDetail) {
  42.         this.addressDetail = addressDetail;
  43.     }
  44. }
  1. package model;
  2. import java.util.HashSet;
  3. import java.util.Set;
  4. /**
  5.  * User entity.
  6.  * 
  7.  * @author MyEclipse Persistence Tools
  8.  */
  9. public class User implements java.io.Serializable {
  10.     // Fields
  11.     private Integer userId;
  12.     private String userName;
  13.     private Set addresses = new HashSet(0);
  14.     // Constructors
  15.     /** default constructor */
  16.     public User() {
  17.     }
  18.     /** minimal constructor */
  19.     public User(String userName) {
  20.         this.userName = userName;
  21.     }
  22.     /** full constructor */
  23.     public User(String userName, Set addresses) {
  24.         this.userName = userName;
  25.         this.addresses = addresses;
  26.     }
  27.     // Property accessors
  28.     public Integer getUserId() {
  29.         return this.userId;
  30.     }
  31.     public void setUserId(Integer userId) {
  32.         this.userId = userId;
  33.     }
  34.     public String getUserName() {
  35.         return this.userName;
  36.     }
  37.     public void setUserName(String userName) {
  38.         this.userName = userName;
  39.     }
  40.     public Set getAddresses() {
  41.         return this.addresses;
  42.     }
  43.     public void setAddresses(Set addresses) {
  44.         this.addresses = addresses;
  45.     }
  46. }

由于是双向关联,因此生成的2个POJO对象都会持有对方对象。并且1对N中,1方持有N方Set集合,N方持有1方单个对象。

 

下面是生成的映射配置:

Address.hbm.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  4. <!-- 
  5.     Mapping file autogenerated by MyEclipse Persistence Tools
  6. -->
  7. <hibernate-mapping>
  8.     <class name="model.Address" table="address" catalog="email">
  9.         <id name="addressId" type="java.lang.Integer">
  10.             <column name="address_id" />
  11.             <generator class="identity" />
  12.         </id>
  13.         <many-to-one name="user" class="model.User" fetch="select">
  14.             <column name="user_id" not-null="true" />
  15.         </many-to-one>
  16.         <property name="addressDetail" type="java.lang.String">
  17.             <column name="address_detail" length="45" />
  18.         </property>
  19.     </class>
  20. </hibernate-mapping>
User.hbm.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  4. <!-- 
  5.     Mapping file autogenerated by MyEclipse Persistence Tools
  6. -->
  7. <hibernate-mapping>
  8.     <class name="model.User" table="user" catalog="email">
  9.         <id name="userId" type="java.lang.Integer">
  10.             <column name="user_id" />
  11.             <generator class="identity" />
  12.         </id>
  13.         <property name="userName" type="java.lang.String">
  14.             <column name="user_name" length="45" not-null="true" />
  15.         </property>
  16.         <set name="addresses" inverse="true">
  17.             <key>
  18.                 <column name="user_id" not-null="true" />
  19.             </key>
  20.             <one-to-many class="model.Address" />
  21.         </set>
  22.     </class>
  23. </hibernate-mapping>

双向1:N关系基本配置很容易套格式,要注意的是在1方配置inverse="true",意思就是将控制方向交给N方会比较高效一点:)。具体后面解释inverse的概念。

 

下面是一个简单的TestCase,演示保存操作:)

  1. import java.util.HashSet;
  2. import java.util.Set;
  3. import model.Address;
  4. import model.User;
  5. import org.hibernate.HibernateException;
  6. import org.hibernate.Session;
  7. import org.hibernate.SessionFactory;
  8. import org.hibernate.cfg.Configuration;
  9. import org.junit.Before;
  10. import org.junit.Test;
  11. public class TestCase2 {
  12.     Session session = null;
  13.     @Before
  14.     // 读取classpath下的配置文件hibernate.cfg.xml
  15.     // current_session_context_class=thread,show_sql=true
  16.     public void getSession() {
  17.         try {
  18.             Configuration cfg = new Configuration().configure();
  19.             SessionFactory sf = cfg.buildSessionFactory();
  20.             session = sf.getCurrentSession();
  21.         } catch (HibernateException e) {
  22.             e.printStackTrace();
  23.         }
  24.     }
  25.     
  26.     @Test
  27.     public void BothSide() {
  28.         session.beginTransaction();
  29.         User u = new User();
  30.         u.setUserName("hello");
  31.         
  32.         //new Address
  33.         Address add = new Address();
  34.         add.setAddressDetail("luoyu road 1037#");
  35.         u.getAddresses().add(add);
  36.         
  37.         session.save(u);
  38.         session.getTransaction().commit();
  39.     }
  40. }

BothSide()方法中创建了一个User,一个Address,然后save,run一下用例,查看到Hibernate执行了下面的操作:

    insert     into      user         (user_name)      values         (?)

只保存了user,如果目的就是象方法所写 save(u),那么就是对的。但是更新了User的同时也想保存这个Address怎么办?

 

想同时保存User和Address,需要做如下两处修改:

1.在User.hbm.xml 17行写上cascade="all"(对User的所有操作均级联到Address表上)

2.在BothSide() 39-40行中添加  add.setUser(u); (由于address的user_id外键字段不需为空,不给它赋值就会报错)

具体见下:

User.hbm.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  3. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  4. <!-- 
  5.     Mapping file autogenerated by MyEclipse Persistence Tools
  6. -->
  7. <hibernate-mapping>
  8.     <class name="model.User" table="user" catalog="email">
  9.         <id name="userId" type="java.lang.Integer">
  10.             <column name="user_id" />
  11.             <generator class="identity" />
  12.         </id>
  13.         <property name="userName" type="java.lang.String">
  14.             <column name="user_name" length="45" not-null="true" />
  15.         </property>
  16.         <set name="addresses" inverse="true" cascade="all">
  17.             <key>
  18.                 <column name="user_id" not-null="true" />
  19.             </key>
  20.             <one-to-many class="model.Address" />
  21.         </set>
  22.     </class>
  23. </hibernate-mapping
  1.     @Test
  2.     public void BothSide() {
  3.         session.beginTransaction();
  4.         User u = new User();
  5.         u.setUserName("hello");
  6.         
  7.         //new Address
  8.         Address add = new Address();
  9.         add.setAddressDetail("luoyu road 1037#");
  10.         add.setUser(u);
  11.         //add Address to user
  12.         u.getAddresses().add(add);
  13.         
  14.         session.save(u);
  15.         session.getTransaction().commit();
  16.     }

      上面这段代码之所以需要添加add.setUser(u),最根本的原因就是上面提到的:我在在User方配置了inverse=true.意思就是“双方的关系交给Address你来管理,User我不负责维护关系”,因此User也不会主动去填充Address方的user_id.

      然而,在维护关系的Address一方,我们访问每一个Address对象的时候,都可以获取到User对象.