Hibernate 关联映射

Hibernate 关联映射

 

1. 单向N-1关联

 

    单向N-1关联只需要从N的一端访问1的一端.

    如,多人住同一地址,只需要在人的实体端找到地址实体,无需关心一个地址的所有人.

    (Person类有个Address类型的Field,而Address类无需关联Person)

    

1.1 无连接表的N-1关联(基于外键)

 

    Person端增加了Address,该属性不是一个普通的组件,而是引用另一个持久化的类.

    使用<many-to-one>在N端(Person端)增加一个外键(关联到address表的主键address_id).

    

    <!-- N-1无连接关联 cascade指定哪些持久化操作会从主表记录级联到从表记录 -->

    <many-to-one name="address" cascade="all" class="Address" column="address_id" />

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +------------+--------------+------+-----+---------+----------------+

    | Field      | Type         | Null | Key | Default | Extra          |

    +------------+--------------+------+-----+---------+----------------+

    | person_id  | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name       | varchar(255) | NO   |     | NULL    |                |

    | age        | int(11)      | YES  |     | NULL    |                |

    | address_id | int(11)      | YES  | MUL | NULL    |                |

    +------------+--------------+------+-----+---------+----------------+

    

1.2 有连接表的N-1关联

    (基于连接表,需要第三张表,保存两个表的id对应关系,这个表中,personid是唯一的,

    因为一个person只能属于一个address)

    join (P436)

 

    <!-- 有连接表的N-1关联(基于连接表,需要第三张表,保存两个表的id对应关系) -->

    <join table="person_address">

      <!-- 本表主键 -->

      <key column="person_id" />

      <!-- 1端表的主键 -->

      <many-to-one name="address" cascade="all" class="Address" column="address_id" />  

    </join>

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +-----------+--------------+------+-----+---------+----------------+

    | Field     | Type         | Null | Key | Default | Extra          |

    +-----------+--------------+------+-----+---------+----------------+

    | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name      | varchar(255) | NO   |     | NULL    |                |

    | age       | int(11)      | YES  |     | NULL    |                |

    +-----------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_address;

    +------------+---------+------+-----+---------+-------+

    | Field      | Type    | Null | Key | Default | Extra |

    +------------+---------+------+-----+---------+-------+

    | person_id  | int(11) | NO   | PRI | NULL    |       |

    | address_id | int(11) | YES  | MUL | NULL    |       |

    +------------+---------+------+-----+---------+-------+

 

2. 单向1-1关联

 

2.1 基于外键的1-1关联(无连接的)

    

    基本同无连接的N-1,但是需要增加一个unique=true.表示在person表中,address_id也是唯一的(不可重复).

    这样一个person对应一个address,一个address也只能对应一个person

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +------------+--------------+------+-----+---------+----------------+

    | Field      | Type         | Null | Key | Default | Extra          |

    +------------+--------------+------+-----+---------+----------------+

    | person_id  | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name       | varchar(255) | NO   |     | NULL    |                |

    | age        | int(11)      | YES  |     | NULL    |                |

    | address_id | int(11)      | YES  | UNI | NULL    |                |

    +------------+--------------+------+-----+---------+----------------+

    

2.2 有连接表的单向1-1

 

    基本同1.2,需要在many-to-one中新增一个属性,unique=true

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +-----------+--------------+------+-----+---------+----------------+

    | Field     | Type         | Null | Key | Default | Extra          |

    +-----------+--------------+------+-----+---------+----------------+

    | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name      | varchar(255) | NO   |     | NULL    |                |

    | age       | int(11)      | YES  |     | NULL    |                |

    +-----------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_address;

    +------------+---------+------+-----+---------+-------+

    | Field      | Type    | Null | Key | Default | Extra |

    +------------+---------+------+-----+---------+-------+

    | person_id  | int(11) | NO   | PRI | NULL    |       |

    | address_id | int(11) | YES  | UNI | NULL    |       |

    +------------+---------+------+-----+---------+-------+

    

2.3 基于主键的1-1关联.

 

    后端的1先有了,前端的1后生产,前端的1的主键有关联的实体负责生成.

    此时address作为主表,有主键,再生成person是,person的主键根据address的主键生成.

    因为person和address是一一对应的,所以他们两个可以共享一个id.

    因为先生成address,所以person的主键由关联的address来提供.

    此时生成的表,只有person_id了,值就是address表中address_id

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +-----------+--------------+------+-----+---------+-------+

    | Field     | Type         | Null | Key | Default | Extra |

    +-----------+--------------+------+-----+---------+-------+

    | person_id | int(11)      | NO   | PRI | NULL    |       |

    | name      | varchar(255) | NO   |     | NULL    |       |

    | age       | int(11)      | YES  |     | NULL    |       |

    +-----------+--------------+------+-----+---------+-------+

    

    此种方式导致 新建一个person后,其对应的address无法更新?

    

    配置:

    <!-- 主键 单向1-1关联 -->

    <id name="id" column="person_id">

      <!-- 主键生成策略是foreign,表示根据关联类的主键来生成该实体的主键 -->

      <generator class="foreign">

        <param name="property">address</param>

      </generator>

    </id>

    

    <!-- 下面映射基于主键的1-1关联 -->

    <one-to-one name="address" />

    

3. 单向1-N关联

 

   持久化类里需要使用集合属性,而这个集合属性数据来自其他的表,且该表已经有映射的对象了.

   (与之前的映射集合元素不一样,之前是使用element,且没有映射对象.,比如之前没有Address这个类),

   这里element改成one-to-many

   

3.1 无连接表的单向1-N

 

     <!-- 无连接表的单向 1-N -->

     <set name="allAddress" >

       <key column="person_id"/>

       <one-to-many class="Address" />

     </set>

 

    //创建新地址

    Address address2 = new Address("三山街");

    Address address3 = new Address("夫子庙");

    session.persist(address2);//这里需要先持久化否则后面add会报错

    session.persist(address3);

    

    aGuy.getAllAddress().add(address2);

    aGuy.getAllAddress().add(address3);

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    | person_id     | int(11)      | YES  | MUL | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +-----------+--------------+------+-----+---------+----------------+

    | Field     | Type         | Null | Key | Default | Extra          |

    +-----------+--------------+------+-----+---------+----------------+

    | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name      | varchar(255) | NO   |     | NULL    |                |

    | age       | int(11)      | YES  |     | NULL    |                |

    +-----------+--------------+------+-----+---------+----------------+

    

    一个person对应N个address

    mysql> select * from address_inf;

    +------------+---------------+-----------+

    | address_id | addressDetail | person_id |

    +------------+---------------+-----------+

    |          1 | 新街口        |      NULL |

    |          2 | 三山街        |         1 |

    |          3 | 夫子庙        |         1 |

    +------------+---------------+-----------+

 

3.2 有连接表的单向1-N关联

 

     <!-- 有连接表的单向 1-N 使用 many-to-many,但需要设置unique="true" -->

     <set name="allAddress"  table="person_address">

       <key column="person_id"/>

       <many-to-many class="Address" column="address_id" unique="true"/>

     </set>

     

     mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +-----------+--------------+------+-----+---------+----------------+

    | Field     | Type         | Null | Key | Default | Extra          |

    +-----------+--------------+------+-----+---------+----------------+

    | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name      | varchar(255) | NO   |     | NULL    |                |

    | age       | int(11)      | YES  |     | NULL    |                |

    +-----------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_address;

    +------------+---------+------+-----+---------+-------+

    | Field      | Type    | Null | Key | Default | Extra |

    +------------+---------+------+-----+---------+-------+

    | person_id  | int(11) | NO   | PRI | NULL    |       |

    | address_id | int(11) | NO   | PRI | NULL    |       |

    +------------+---------+------+-----+---------+-------+

    

4. 单向N-N关联

 

   和有连接的单向1-N关联类似,配置时去掉many-to-many的unique=true

   

   <!-- 单向N-N关联 -->

     <set name="allAddress"  table="person_address">

       <key column="person_id"/>

       <many-to-many class="Address" column="address_id"/>

     </set>

   

   mysql> desc address_inf;

  +---------------+--------------+------+-----+---------+----------------+

  | Field         | Type         | Null | Key | Default | Extra          |

  +---------------+--------------+------+-----+---------+----------------+

  | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

  | addressDetail | varchar(255) | YES  |     | NULL    |                |

  +---------------+--------------+------+-----+---------+----------------+

  

  mysql> desc person_senior_inf;

  +-----------+--------------+------+-----+---------+----------------+

  | Field     | Type         | Null | Key | Default | Extra          |

  +-----------+--------------+------+-----+---------+----------------+

  | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

  | name      | varchar(255) | NO   |     | NULL    |                |

  | age       | int(11)      | YES  |     | NULL    |                |

  +-----------+--------------+------+-----+---------+----------------+

  

  mysql> desc person_address;

  +------------+---------+------+-----+---------+-------+

  | Field      | Type    | Null | Key | Default | Extra |

  +------------+---------+------+-----+---------+-------+

  | person_id  | int(11) | NO   | PRI | NULL    |       |

  | address_id | int(11) | NO   | PRI | NULL    |       |

  +------------+---------+------+-----+---------+-------+

  

5. 双向1-N管理

 

5.1 无连接表的双向1-N关联

 

    N端需要修改<many-to-one>,1的一段需要增加<set>,<set>里面增加

    <key>子元素映射外键,并使用<one-to-many>子元素映射关联属性.

    

     <!-- 无连接表 双向1-N关联,1的那端  -->

     <set name="allAddressWithPerson" inverse="true">

       <key column="person_id"/>

       <one-to-many class="AddressWithPerson"/>

     </set>

     

    <!-- 无连接表 双向1-N关联,N 的那端  -->

    <!-- 必须指定列名为person_id,与关联实体中key元素的column值相同 -->

    <many-to-one name="person" class="Person" column="person_id" not-null="true" />

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    | person_id     | int(11)      | NO   | MUL | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    

    mysql> desc person_senior_inf;

    +-----------+--------------+------+-----+---------+----------------+

    | Field     | Type         | Null | Key | Default | Extra          |

    +-----------+--------------+------+-----+---------+----------------+

    | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name      | varchar(255) | NO   |     | NULL    |                |

    | age       | int(11)      | YES  |     | NULL    |                |

    +-----------+--------------+------+-----+---------+----------------+

    

    因为N的那端已经有了1端的引用,所有在Java代码中的步骤如下(P446):

    (1) 创建一个1端实例,并持久化

    (2) 创建一个N端的实例,使用set方法将(1) 中实例set进来

    (3) 持久化(2)中N端实例

    

  public void test()

  {

    Session session = HibernateUtil.currentSession();

    Transaction tx = session.beginTransaction();

    

    Person aGuy = new Person();

    aGuy.setName("Frank");

    aGuy.setAge(28);

    

    //持久化1端实例

    session.save(aGuy);

    

    //创建N端实例

    AddressWithPerson addressWithPerson1 = new AddressWithPerson("新街口 with person");

    addressWithPerson1.setPerson(aGuy);

    //这里表示通过N端对象来设置关联关系,因为在1端配置了,inverse="true"

    //表示不能用Person的Set的add方法设置关联关系了.

    session.persist(addressWithPerson1);

    

    tx.commit();

    HibernateUtil.closeSession();

    

  }

  

5.2 有 连接表的双向1-N关联

 

    有 连接表 的双向1-N,1端使用set,N端,相当于N-1,使用join.

    

    <!-- 有连接表的 双向1-N关联 1的那端 -->

     <set name="allAddressWithPerson" inverse="true" table="person_address">

       <key column="person_id"/>

       <many-to-many class="AddressWithPerson" column="address_id" unique="true" />

     </set>

     

     <!-- 有 连接表 的 双向1-N关联 N的那端 -->

    <join table="table_address">

      <key column="address_id" />

      <many-to-one name="person" column="person_id" not-null="true" />

    </join>

    

    mysql> desc address_inf;

    +---------------+--------------+------+-----+---------+----------------+

    | Field         | Type         | Null | Key | Default | Extra          |

    +---------------+--------------+------+-----+---------+----------------+

    | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

    | addressDetail | varchar(255) | YES  |     | NULL    |                |

    +---------------+--------------+------+-----+---------+----------------+

    2 rows in set (0.02 sec)

    

    mysql> desc person_senior_inf;

    +-----------+--------------+------+-----+---------+----------------+

    | Field     | Type         | Null | Key | Default | Extra          |

    +-----------+--------------+------+-----+---------+----------------+

    | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

    | name      | varchar(255) | NO   |     | NULL    |                |

    | age       | int(11)      | YES  |     | NULL    |                |

    +-----------+--------------+------+-----+---------+----------------+

    3 rows in set (0.00 sec)

    

    mysql> desc person_address;

    +------------+---------+------+-----+---------+-------+

    | Field      | Type    | Null | Key | Default | Extra |

    +------------+---------+------+-----+---------+-------+

    | address_id | int(11) | NO   | PRI | NULL    |       |

    | person_id  | int(11) | NO   | MUL | NULL    |       |

    +------------+---------+------+-----+---------+-------+

    

    mysql> select * from person_address;

    +------------+-----------+

    | address_id | person_id |

    +------------+-----------+

    |          1 |         1 |

    |          2 |         1 |

    +------------+-----------+

    2 rows in set (0.00 sec)

    

6. 双向 N-N关联

 

   双向N - N 关联需要在两端都使用set集合.双向N - N关联只能采用连接表

   

   <!-- 双向N-N关联 只能采用连接表 --> 

     <set name="allAddressWithPerson" table="person_address">

       <key column="person_id"/>

       <many-to-many class="AddressWithPerson" column="address_id" />

     </set>

   

   <!-- 双向N-N关联 只能采用连接表 --> 

     <set name="persons" table="person_address">

       <key column="address_id"/>

       <many-to-many class="Person" column="person_id" />

     </set>

     

   

   

   mysql> desc address_inf;

  +---------------+--------------+------+-----+---------+----------------+

  | Field         | Type         | Null | Key | Default | Extra          |

  +---------------+--------------+------+-----+---------+----------------+

  | address_id    | int(11)      | NO   | PRI | NULL    | auto_increment |

  | addressDetail | varchar(255) | YES  |     | NULL    |                |

  +---------------+--------------+------+-----+---------+----------------+

  

  mysql> desc person_senior_inf;

  +-----------+--------------+------+-----+---------+----------------+

  | Field     | Type         | Null | Key | Default | Extra          |

  +-----------+--------------+------+-----+---------+----------------+

  | person_id | int(11)      | NO   | PRI | NULL    | auto_increment |

  | name      | varchar(255) | NO   |     | NULL    |                |

  | age       | int(11)      | YES  |     | NULL    |                |

  +-----------+--------------+------+-----+---------+----------------+

  

  mysql> desc person_address;

  +------------+---------+------+-----+---------+-------+

  | Field      | Type    | Null | Key | Default | Extra |

  +------------+---------+------+-----+---------+-------+

  | person_id  | int(11) | NO   | PRI | NULL    |       |

  | address_id | int(11) | NO   | PRI | NULL    |       |

  +------------+---------+------+-----+---------+-------+

  双向N-N时,在两个id上创建联合主键:primary key (address_id, person_id)

   

7. 双向1-1关联

 

   修改两个类,存放对对方的引用,并加上getter和setter

   

7.1 基于外键的双向 1-1关联

 

    <!-- 基于外键的 双向 1-1 关联 person端-->

    <one-to-one name="addressWithPerson" property-ref="person" />

  

    <!-- 基于外键的 双向 1-1 关联 address端-->

    <many-to-one name="person" unique="true" column="person_id" not-null="true" />

    

    以下略.(P450)

    

7.2 基于主键的 双向 1-1 关联(P451)

 

7.3 有连接表的双向1-1关联(P452)

 

   

   

你可能感兴趣的:(Hibernate)