Hibernate(四)

来源:互联网 发布:拼多多互刷平台源码 编辑:程序博客网 时间:2024/05/05 02:08

* 继承映射
论坛中的文章有主题和回复两种:Topic和Reply,他们都是文章,都有content与
author属性,即继承自同一个父类。

可以使用两种方式映射:
  a) 每个继承结构一张表,需要一个字段用于区分子类的具体类型;
  b) 每个类一张表,这是就有三张表,各自都只包含自己的属性,子类对应的表
     的主键也做为外键引用超类对应的表的主键。

** 每个继承结构一张表 (subclass)
<class name="Article" table="itcast_article" discriminator-value="A">
...
<!-- 指定一个列,用于区分子类的具体类型(鉴别器) -->
<discriminator column="class" type="string"></discriminator>
...
<subclass name="Topic" discriminator-value="T">
    <property name="title"></property>
</subclass>
<subclass name="Reply" discriminator-value="R">
    <property name="floor"></property>
</subclass>

discriminator是指定用于区分不同子类的列,type属性指定这个列的类型,如果
不指定,默认为string;这个元素要写在id元素的后面,不要把顺序弄错了。子
类用subclass元素指定,其中的discriminator-value用于指定代表这个子类的值,
这个值要是唯一的。如果不指定,默认值是这个子类的全限定名。

获取实体时,使用:
  session.get(Article.class, 1);
返回的记录将会根据这条记录的鉴别器值进行判断返回相应的对象实例。例如,
如果是T,返回一个Topic的实例;如果是R,则返回一个Reply的实例。

** 每个类一张表 (joned-subclass)
...
<joined-subclass name="Topic" table="itcast_topic">
    <key column="id"></key>
    <property name="title"></property>
</joined-subclass>
...

其中key指定的是子类表的主键,同时也会做为外键引用父类表的主键。

package cn.itcast.demo.entities;

public class Article {

 private int id;
 private User author;

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public User getAuthor() {
  return author;
 }

 public void setAuthor(User author) {
  this.author = author;
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + id;
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  final Article other = (Article) obj;
  if (id != other.id)
   return false;
  return true;
 }

}
package cn.itcast.demo.entities;

public class Topic extends Article {

 private String title;

 public String getTitle() {
  return title;
 }

 public void setTitle(String title) {
  this.title = title;
 }

}
package cn.itcast.demo.entities;

public class Reply extends Article {

 private int floor;

 public int getFloor() {
  return floor;
 }

 public void setFloor(int floor) {
  this.floor = floor;
 }

}
<?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="cn.itcast.demo.entities">
 <class name="Article" table="itcast_artile" discriminator-value="Article">
  <id name="id">
   <generator class="native" />
  </id>

  <!--
   <discriminator column="class" type="string"></discriminator>
  -->

  <many-to-one name="author" column="authorId"></many-to-one>

  <!--
   <subclass name="Topic" discriminator-value="Topic">
   <property name="title"></property>
   </subclass>
   <subclass name="Reply" discriminator-value="Reply">
   <property name="floor"></property>
   </subclass>
  -->

  <joined-subclass name="Topic" table="itcast_topic">
   <key column="topicId"></key>
   <property name="title"></property>
  </joined-subclass>
  <joined-subclass name="Reply" table="itcast_reply">
   <key column="replyId"></key>
   <property name="floor"></property>
  </joined-subclass>

 </class>
</hibernate-mapping>

package cn.itcast.demo.test;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test;

import cn.itcast.demo.entities.*;

public class ArticleTest {

 @Test
 public void test() {
  SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
  Session session = sessionFactory.openSession();
  Transaction tx = session.beginTransaction();

  // Topic t = new Topic();
  // Reply r = new Reply();
  // Article a = new Article();
  // session.save(t);
  // session.save(r);
  // session.save(a);

  Object o = session.get(Article.class, 2);
  System.out.println(o);

  tx.commit();
  session.close();
 }
}

 

<!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="dialect">org.hibernate.dialect.MySQL5Dialect</property>
  <property name="connection.url">jdbc:mysql:///test</property>
  <property name="connection.username">root</property>
  <property name="connection.password">root</property>
  <property name="connection.driver_class">com.mysql.jdbc.Driver</property>

  <property name="hbm2ddl.auto">update</property>
  <property name="show_sql">true</property>
  <property name="format_sql">false</property>

  <property name="current_session_context_class">thread</property>
  <property name="transaction.auto_close_session">false</property>

  <!-- 使用二级缓存 -->
  <property name="cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

  <mapping resource="cn/itcast/demo/entities/User.hbm.xml" />
  <mapping resource="cn/itcast/demo/entities/Group.hbm.xml" />
  <mapping resource="cn/itcast/demo/entities/IdCard.hbm.xml" />
  <mapping resource="cn/itcast/demo/entities/Role.hbm.xml" />
  <mapping resource="cn/itcast/demo/entities/Article.hbm.xml" />

  <!--
  -->
  <class-cache class="cn.itcast.demo.entities.Group" usage="read-write" />
 </session-factory>
</hibernate-configuration>

 

user.java与group.java代码这里就不在添加,在昨天的blog中已写。因为cascade是在Group.hbm.xml中配置的。
* inverse
此属性表示 "是否放弃维护关联关系",在one-to-many和many-to-many中使用,
默认值是"false"。  维护关联关系是指在Java里两个对象关联时,对数据库表中
的数据产生影响。在一对多/多对一中,是指设置外键列的值;在多对多中是指在
中间表是增减记录。

设置inverse=true表示放弃维护关联关系,即由对方来维护。在使用时要注意:
  a) 在索引(有序)集合中,不要设置inverse=true,否则不能生成索引值。
  b) 在多对多映射中,不要双方都设置为inverse=true,否则都不维护关系。

维护关联关系总结:
  a) 一对多/多对一:多的一方始终可以维护关系;一的一方可以设置是否维护
    关联关系。
  b) 一对一:只能由 有外键的表对应的实体 来维护关联关系。
  c) 多对多:双方都可以设置是否维护关联关系。
* cascade
Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操
作,常用的cascade值有:
  none(默认值,无级连操作);
  all(所有级连操作);
  save-update(对主对象调用save()或update()或saveOrUpdate()方法时对从对
      象调用saveOrUpdate());
  delete(delete()方法);
其他还有lock,refresh,evict,replicate,persist,merge,delete-orphan等。

同时使用多种级联风格时使用逗号分隔,如 cascade="save-update,delete"。

通常在many-to-one或many-to-many关系中应用级联没有意义。如删除一个用户不
应该删除他所属的组(组中的其他用户怎么办);或删除了一个组不应该把他对
应的权限实体也删除掉(其他组还要用呢)。 一般在one-to-one和one-to-many
中设置级联比较有用。

* 在Set中添加重复的未保存状态的实体
在一对多中,可以通过设置级联 cascade="save-update" 来实现在save()一方的
实体时级联的插入多方的数据,但这时如果集合如果使用的是Set,就会出现只插
入一个记录的现象,这是因为未保存的对象的主键值相等,hashCode()相同并且
equals()为true。

在Set中不能添加重复的元素,是否重复是通过hashCode和equals方法决定的。所
以可以通过重写hashCode与equals方法实现在Set中可以添加多个未保存的实体对
象(有相同的主键值): hashCode:IF id==null THEN return super.hashCode。
<?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="cn.itcast.demo.entities">
 <class name="Group" table="itcast_group">
  <!--
   <cache usage="read-write"/>
  -->
  <id name="id">
   <generator class="native" />
  </id>
  <property name="name" type="string" />

  <!--
  -->

  <set name="users" inverse="true" cascade="save-update">
   <key column="groupId"></key>
   <one-to-many class="User" />
  </set>

  <!--
   <list name="userList" inverse="false" cascade="save-update,delete">
   <key column="groupId"></key>
   <index></index>
   <one-to-many class="User" />
   </list>
  -->

  <many-to-one name="parent" column="parentId" />
  <set name="children">
   <key column="parentId" />
   <one-to-many class="Group" />
  </set>

  <set name="roles" table="itcast_groups_roles" lazy="true" inverse="true">
   <key column="groupId"></key>
   <many-to-many class="Role" column="roleId"></many-to-many>
  </set>

 

 </class>
</hibernate-mapping>


package cn.itcast.demo.test;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test;

import cn.itcast.demo.entities.Group;
import cn.itcast.demo.entities.User;

public class CascadeTest {

 @Test
 public void test() {
  SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
  Session session = sessionFactory.openSession();
  Transaction tx = session.beginTransaction();

  User user = new User();
  User user2 = new User();
  Group group = new Group();

  // user.setGroup(group);
  // group.getUserList().add(user);
  
  group.getUsers().add(user);
  group.getUsers().add(user2);

  System.out.println(group.getUsers().size());
  
  // session.save(user);
  session.save(group);

  // group.setId(31);
  // group = (Group) session.get(Group.class, 30);
  // session.delete(group);

  tx.commit();
  session.close();
 }
 
 public static void main(String[] args) {
  Set<User> set = new HashSet<User>();
  User user = new User();
  User user2 = new User();
 
  set.add(user);
  set.add(user2);
  
  System.out.println(set);
 }
}