关闭

ORM映射

标签: apiormhibernate
146人阅读 评论(0) 收藏 举报
分类:
一.单表映射(单类-单表)
1.主键生成策略(在Xxx.hbm.xml文件中进行配置)
(1) 数据库维护主键
      native:表示根据方言自动选择主键策略:
                 如果使用的是mysql方言,那么,自动选择identity 
                 如果使用的是oracle方言,那么,自动选择sequence 
     identity : 表示采用数据库底层自动增长的方式分配主键:例如:mysql数据库提供auto_increment
     sequence :表示采用序列的方式分配主键:例如:oracle数据库采用sequence方法
(2) 框架维护主键
     increment : 表示根据"select max(id) form 表"获取表中最大值,+1分配主键使用,这样主键生成策略,存在并发问题
     hilo :数据库中生成一张额外的表,用来保存高低算法的高值;框架分配主键时,会从数据库获取这个高值,结合低值,通过一个表达式计算出唯一的一个主键值分配使用。 
(3) 自己维护主键
     assigned : 默认值,在保存前,需要查询主键记录是否存在,验证主键有效性。
2. 日期类型映射
(1) 在POJO类中,并提供相应的set,get方法:
private Date publicDate ;   //java.util.Date
(2) 在配置文件中:
<property name="publicDate" column="PUBLIC_DATE" type="date"></property>
或
<property name="publicDate" column="PUBLIC_DATE" type="time"></property>
或
<property name="publicDate" column="PUBLIC_DATE" type="timestamp"></property>
(3).在测试类中:
@Test
     public void testSave(){
          Book book = new Book(222, "红楼梦");
           book.setPublicData(new Date());
           session.save( book);
     }
3.大对象类型Hibernate的映射:
private Blob imageBlob ; //java.sql.Blob
<property name="imageBlob" type="blob">
     <column name ="IMAGE_BLOB" sql-type="mediumblob" />
</property>

@Test
public void testSave() throws IOException{
     Book book = new Book(778,"红楼梦2");
     book.setPublicDate(new Date());
     FileInputStream in = new FileInputStream("java.jpg"); //默认从当前项目根路径加载图片
     Blob imageBlob = Hibernate.getLobCreator(session).createBlob(in, in.available());
     book.setImageBlob(imageBlob);
     session.save(book);
}
4.特殊属性映射:
     在映射配置文件的class标签上设置特殊属性来动态生成SQL语句:  根据对象的属性值是否为null来动态生成SQL语句,是null的属性就不参与insert或update操作了。
dynamic-insert="true"  动态生成insert语句
dynamic-update="true" 动态生成update语句
5.派生属性:不需要与表进行映射
     它的值来自于formula属性返回结果,它是通过执行一条SQL动态得到的一个结果(SQL语句需要存放到小括号中)
<property name="desc" formula="(select price * count from t_book where t_book.bookId=bookId)"></property>

二.多表映射-单向多对一
1.单向多对一:
多对一:
     例如:多个订单与一个用户之间的关系,就是多对一;
          一个用户可以有多个订单,就是一对多。
单向:
     Customer customer = order.getCustomer();//多对一
     Set<Order> orders = customer.getOrderSet(); //一对多
     只能通过一端去关联另一端就是单向的关联,如果可以通过两端相互访问对端,那么,就是双向的关联;
2.单向多对一关联关系
(1) 从面向对象模型角度
          •建立两个类:
          Order类 :
               private Customer customer ;
          Customer类 :
(2) 从关系模型的角度
•在Order表中增加一个外键,引用Customer表中的主键.

(3) 从映射模型的角度:
Order.hbm.xml
<!--   many-to-one : 完成多对一关系映射
       name : 用于指定关联属性名称
       fetch="join"
 -->
<many-to-one name="customer" class="com.pers.hibernate.pojo.Customer" >
   <!-- 用于指定关系型数据库中的外键 -->
   <column name="CUSTOMER_ID_FK" />
</many-to-one>
3.单向多对一关联关系映射 - 总结:
(1) 保存
     推荐先保存一的一端,再保存多的一端
     如果先保存多的一端,再保存一的一端,会多执行update语句。
          产生多余update语句原因: 在保存多的一端时,由于一的一端还没有保存,所以,外键先空着,等保存了一的一端后,再通过update语句来更新多的一端,将外键维护好;
(2) 查询
     多对一关联查询,默认支持延迟加载的。默认支持延迟加载的。lazy="proxy"
     禁用关联查询延迟加载功能。lazy="false" ;一起发生两条语句;
     采用连接查询关联数据。fetch="join" 直接发生一条左外连接语句,一次性将关联数据查询出来。延迟加载是失效的。
(3) 修改
     可以修改当前对象,也可以通过关联关系获取关联对象,修改关联对象的属性值。
     持久化对象属性值修改,不需要手动执行update()方法,框架会根据脏检查机制自动执行update语句
(4) 删除
     如果有订单关联用户,无法删除用户对象,会报外键约束异常。

三.多表映射_双向多对一(双向一对多)
1.双向多对一和双向一对多是一回事,表示两端都可以关联到对端。
2.双向一对多(多对一 )关联映射:
(1) 从对象模型的角度
     Order
          private Customer customer ;
     Customer
          private Set<Order> orderSet = new HashSet<Order>();
(2) 从关系模型角度
(3) 从映射模型角度
a.Customer.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>
    <class name="com.pers.hibernate.pojo.Customer" table="T_CUSTOMER">
        <id name="customerId" type="java.lang.Integer">
            <column name="CUSTOMER_ID" />
            <generator class="native" />
        </id>
        <property name="customerName" type="java.lang.String">
            <column name="CUSTOMER_NAME" />
        </property>
        <!--
           描述一对多映射关系
           invrse : 反转设置
                inverse="true" 表示当前端放弃维护外键。
           lazy = "true": 默认为true支持延迟加载;
                         设置为false是不支持延迟加载;
                         设置为extra : 支持延迟加载,但是获取集合自身属性时,会发送高效的查询语句。
           cacade : 表示级联操作(主要针对于增,删,改)
                delete : 表示删除当前端对象时,将关联端数据也一起删除
                save-update : 表示保存或更新当前端时,关联端也做相应的保存或更新操作
                all : 表示所有操作都级联。
           order-by="列名:对集合进行排序。

           table = "" :表示当前端关联对方表的表明,这个属性不写可以,如果写,就必须设置和关联方表明一致。
         -->
        <set name="orderSet" inverse="true" cascade="save-update" order-by="orderName DESC,orderId ASC">
            <key>
                <!-- 外键,默认与关联表的主键关联 -->
                <column name="CUSTOMER_ID_FK" />
            </key>
            <one-to-many class="com.pers.hibernate.pojo.Order" />
        </set>
    </class>
</hibernate-mapping>
     b.Order.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>
    <class name="com.pers.hibernate.pojo.Order" table="T_ORDER">
        <id name="orderId" type="java.lang.Integer">
            <column name="ORDER_ID" />
            <generator class="native" />
        </id>
        <property name="orderName" type="java.lang.String">
            <column name="ORDER_NAME" />
        </property>

        <many-to-one name="customer" class="com.pers.hibernate.pojo.Customer" >
            <column name="CUSTOMER_ID_FK" />
        </many-to-one>

    </class>
</hibernate-mapping>
四.基于外键的一对一映射
1.基于外键的一对一映射:
(1) 从关系模型的角度
     一对一是一对多或多对一的特殊情况;
     如果是基于外键的一对一映射,只需要将外键设置为unique约束

(2) 从对象模型的角度
     Husband
          private Wife wife ;
     Wife
          private Husband husband ;
(3) 映射配置:
 a.Husband.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>
    <class name="com.pers.hibernate.pojo.Husband" table="T_HUSBAND">
        <id name="husbandId" type="java.lang.Integer">
            <column name="HUSBAND_ID" />
            <generator class="native" />
        </id>
        <property name="husbandName" type="java.lang.String">
            <column name="HUSBAND_NAME" />
        </property>
        <!-- 表示一对一映射
           查询不带外键一端时,去关联带外键一端默认按照两个主键进行关联查询,这是因为husband不知道如何去关联wife.
           此时,需要设置property-ref属性 :
                告诉husband如何去关联wife对象:取对端关联的属性名称。
         -->
        <one-to-one name="wife" class="com.pers.hibernate.pojo.Wife" property-ref="husband"></one-to-one>
    </class>
</hibernate-mapping>
b.Wife.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>
    <class name="com.pers.hibernate.pojo.Wife" table="T_WIFE">
        <id name="wifeId" type="java.lang.Integer">
            <column name="WIFE_ID" />
            <generator class="native" />
        </id>
        <property name="wifeName" type="java.lang.String">
            <column name="WIFE_NAME" />
        </property>

        <!-- 基于外键的一对一映射,是多对一映射的一种特殊情况
           只需要在<many-to-one>标签上设置unique属性为true,就有多对一变为了一对一
         -->
        <many-to-one name="husband" class="com.pers.hibernate.pojo.Husband" unique="true" column="HUSBAND_ID_FK"></many-to-one>

    </class>
</hibernate-mapping>
2.基于外键一对一映射的注意点:
(1) property-ref属性需要设置,否则,在查询 Husband对象时,他的关联对象查询,会以两个主键进行关联查询,这种查询条件是不对的, 而是应该根据外键进行关联查询,所以,需要设置 property-ref属性,取值:取对端关联的属性名称。
(2) 基于外键的一对一关联映射:查询不带外键一端,去关联带外键一端时,不支持延迟加载

五.基于主键的一对一映射
1.基于主键的一对一:
(1) 从关系模型角度

(2) 从对象模型的角度
     Husband
          private Wife wife ;
     Wife
          private Husband husband ;
 (3) 基于主键一对一映射配置
     a.Wife.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>
    <class name="com.pers.hibernate.pojo.Wife" table="S_WIFE">
        <id name="wifeId" type="java.lang.Integer">
            <column name="WIFE_ID" />

           <!--
                foreign : 基于外键的主键生成策略。
             -->
            <generator class="foreign">
                <param name="property">husband</param>
            </generator>

        </id>
        <property name="wifeName" type="java.lang.String">
            <column name="WIFENAME" />
        </property>

        <!--
           constrained="true" : 表示给外键强制增加外键约束。
         -->
        <one-to-one name="husband" class="com.pers.hibernate.pojo.Husband"constrained="true"></one-to-one>
    </class>
</hibernate-mapping>
     b.Husband.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>
    <class name="com.pers.hibernate.pojo.Husband" table="S_HUSBAND">
        <id name="husbandId" type="java.lang.Integer">
            <column name="HUSBAND_ID" />
            <generator class="native" />
        </id>
        <property name="husbandName" type="java.lang.String">
            <column name="HUSBAND_NAME" />
        </property>
        <one-to-one name="wife" class="com.pers.hibernate.pojo.Wife"></one-to-one>
    </class>
</hibernate-mapping>
2.说明:基于主键的一对一映射总结
(1) 基于主键一对一映射,无论先保存哪一端,都会先保存不带外键一端。
(2) 查询不带外键一端,关联一端查询是不支持延迟加载的。

六.映射多对多:
1.映射多对多:
(1) 从关系模型的角度
     数据库中多对多的两张表不能直接描述多对多的关系,一般都是需要增加一张中间表来描述多对多关系的;
     中间表有两个外键,分别引用多对多两个表的主键;中间表的两个外键同时又作为联合主键,表示数据的唯一性

(2) 从对象模型的角度
     Student :
           private Set<Course> courseSet = new HashSet<Course>();
     Course :
           private Set<Student> studentSet = new HashSet<Student>();
(3) 从映射模型的角度
     a.Student.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>
    <class name="com.pers.hibernate.pojo.Student" table="T_STUDENT">
        <id name="studentId" type="java.lang.Integer">
            <column name="STUDENT_ID" />
            <generator class="native" />
        </id>
        <property name="studentName" type="java.lang.String">
            <column name="STUDENT_NAME" />
        </property>

        <set name="courseSet" table="STUDENT_COURSE_FK" >
            <key>
                <column name="STUDENT_ID_FK" />
            </key>
                <many-to-many class="com.pers.hibernate.pojo.Course" column="COURSE_ID_FK"></many-to-many>
        </set>
    </class>
</hibernate-mapping>
     b.Course.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>
    <class name="com.pers.hibernate.pojo.Course" table="T_COURSE">
        <id name="courseId" type="java.lang.Integer">
            <column name="COURSE_ID" />
            <generator class="native" />
        </id>
        <property name="courseName" type="java.lang.String">
            <column name="COURSE_NAME" />
        </property>

           <!--
               table : 设置中间表名称
               默认情况下,两端都会维护中间表外键,两端都维护时,会出现联合主键重复异常
               解决办法:让其中一端放弃维护外键
               只需要在其中一端的set标签上设置inverse="true"
            -->
        <set name="studentSet" table="STUDENT_COURSE_FK" inverse="true">
            <key>
                <!-- 当前端在中间表的外键 -->
                <column name="COURSE_ID_FK" />
            </key>
                <many-to-many class="com.pers.hibernate.pojo.Student" column="STUDENT_ID_FK"></many-to-many>
        </set>
    </class>
</hibernate-mapping>
(4) 在测试类中的程序:
@Test
     public void test(){
          Student s1 = new Student(null ,"zhangsan" );
          Student s2 = new Student(null ,"zhangsan" );
          Course c1 = new Course(null ,"语文" );
          Course c2 = new Course(null ,"数学" );

          s1.getCourseSet().add(c1);
          s1.getCourseSet().add(c2);
          s2.getCourseSet().add(c1);

           /*c2.getCourseSet().add(s1);
          c2.getCourseSet().add(s1);
          c2.getCourseSet().add(s2);*/

           session.save(s1);
           session.save(s2);
           session.save(c1);
           session.save(c2);
     }

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:15363次
    • 积分:1287
    • 等级:
    • 排名:千里之外
    • 原创:110篇
    • 转载:4篇
    • 译文:0篇
    • 评论:3条
    最新评论