《精通Hibernate》学习(3)——对象关系映射基础

 1、持久化类的属性和访问方法

(1)持久化类简介

 

在Hibernate中持久化类的访问方法有两个调用者,一个是Java应用程序,一个是Hibernate。值得注意的是,Java应用程序不能访问持久化类的private类型的getXXX()、setXXX(),而Hibernate没有这样的限制。

 

(2)基本类型属性和包装类型属性

Java有8种基本类型:byte,short,char,int,long,float,double,boolean;与之对应的Java提供了8种包装类型:Byte,Short,Character,Integer,Long,Float,Double,Boolean。基本类型与包装类型之间可以如下简单转换:

 

double prD=1;
//把double基本类型转换成Double包装类型
Double wrD=new Double(prD);
//把Double包装类型转换成double基本类型
prD=wrD.doubleValue();

Hibernate两种类型都是支持的。

 

(3)在持久化类的访问方法中加入程序逻辑

(a)在Customer类的getName()和setName()方法中加入程序逻辑


假如在Customer类中有firstname属性和lastname属性,但是没有name属性,而数据库CUSTOMERS表中只有NAME字段。当Hibernate从数据库中取得了CUSTOMERS表的NAME字段值后,会调用setName()方法,此时应该让Hibernate通过setName()方法来自动设置firstname属性和lastname。故要在setName()方法中加入额外的程序逻辑。

  public String getName(){
    return firstname+ " "+lastname;
 }

 public void setName(String name){
   StringTokenizer t=new StringTokenizer(name);
   firstname=t.nextToken();
   lastname=t.nextToken();
 }

在映射文件中此时直接映射name即可,无需映射firstname等。

<property name="name" column="NAME">

尽管在Customer类中没有定义name属性,由于Hibernate并不会直接访问name属性,而是通过getName()和setName()方法。只要在Customer.hbm.xml文件中映射了name属性,HQL语句就能访问:

Query query=seesion.createQuery("from Customer as c where c.name='Tom'");


但是如果把Customer.hbm.xml文件中name属性配置为:

<property name="name" column="NAME" access="field">

程序会直接去访问Customer实例中的name属性,就会出现异常。

 

 

(b)在Customer类的setOrders()方法中加入程序逻辑

假定Customer类中有一个avgPrice属性,表示订单的平均价格,取值为它所关联Order对象的price的平均值。在CUSTOMERS表中没有AVG_PRICE字段。可以如下操作:

 

 public Double getAvgPrice(){
      return this.avgPrice;
  }
  private void setAvgPrice( Double avgPrice ){
      this.avgPrice = avgPrice;
  }
  public Double getTotalPrice(){
      return this.totalPrice;
  }
  private void setTotalPrice( Double totalPrice ){
      this.totalPrice = totalPrice;
  }

  public void setOrders( Set orders ){
    this.orders = orders;
    calculatePrice();
  }
  public Set getOrders(){
    return orders;
  }//定义为一个Set
  private void calculatePrice(){
      double avgPrice = 0.0;
      double totalPrice = 0.0;
      int count=0;
//迭代计算orders里面所有price
      if ( getOrders() != null ){
        Iterator iter = getOrders().iterator();
        while( iter.hasNext() ){
          double orderPrice = ((Order)iter.next()).getPrice();
          totalPrice += orderPrice;
          count++;
        }
        // Set the price for the order from the calcualted value
        avgPrice=totalPrice/count;
        setAvgPrice( new Double(avgPrice) );
      }
  }

在Customer.hbm.xml文件不用映射avgPrice,因为Hibernate不会直接访问avgPrice属性,也不会调用getavgPrice()和setavgPrice().

 

(c)在Customer类的setSex()方法中加入数据验证逻辑

 在持久化类的访问方法中,还可以加入数据验证逻辑。

 public char getSex(){
    return this.sex;
  }
  public void setSex(char sex){
      if(sex!='F' && sex!='M'){
        throw new IllegalArgumentException("Invalid Sex");
      }
      this.sex =sex ;
  }

 

(4)设置派生属性

持久化类并非所有属性都直接和表的字段匹配,持久化类的有些属性是可以在运行的时候得出的,这些称作派生属性。正如之前的avgPrice属性,该方案包括两个步骤:

  • 在映射文件中不映射avgPrice属性

  • 在Customer类的setOrders()方法中加入程序逻辑,自动为avgPrice属性赋值。 

 除了这种方法来设置派生属性,还可以如下解决:

利用<property>元素的formula属性。formula属性用来设置一个SQL表达式,Hibernate将根据它来计算派生属性的值。以Customer类的totalPrice属性为例:

<property name="totalPrice" formula="(select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=ID)"/>

 

在Hibernate从数据库中查询Customer对象时,若查询totalPrice,即:

select totalPrice from CUSTOMERS;

使用formula属性后,上面的查询语句就会自动地被替代成:

select (select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=1) from CUSTOMERS;

如果子句的查询结果为空,那么上述的语句就会出现异常。解决方法是:将totalPrice的属性定义为Double包装类型。

 

(5)控制insert和update语句

 Hibernate在初始化阶段,就会根据映射文件的映射信息,为所有的持久化类定义以下的SQL语句。

 

 以上SQL语句中的“?”代表JDBC PreparedStatement中的参数。这些SQL语句都存放在SessionFactory的内置缓存中,当执行Session的save()、update()、delete() 、load()和get()方法的时候,将从缓存中找到对应预定义的SQL语句,再把具体的参数值绑定到该SQL语句中。

 

 

 

2、创建命名策略

 

还有一直一种方法是实现Hibernate的org.hibernate.cfg.NamingStrategy接口,对于这个接口Hibernate提供了两种参考实现类:org.hibernate.cfg.defaultNamingStrategy和org.hibernate.cfg.ImprovedNamingStrategy类。

MyNamingStrategy.java

 

package mypack;
import org.hibernate.cfg.ImprovedNamingStrategy;
import org.hibernate.util.StringHelper;
public class MyNamingStrategy extends ImprovedNamingStrategy {
   public String classToTableName(String className) {
        return  StringHelper.unqualify(className).toUpperCase()+'S';//classname转化成大写字母+S就是对应的表名
   }
   public String propertyToColumnName(String propertyName) {
       return propertyName.toUpperCase();
   }
   public String tableName(String tableName) {
       return tableName;
   }
   public String columnName(String columnName) {
       return columnName;
   }
   public String propertyToTableName(String className, String propertyName) {
       return classToTableName(className) + '_' +
            propertyToColumnName(propertyName);
   }
}


使用命名策略后可以更好的将数据库中表名、列名对象化成类中的对象。

3、实例

 本节的代码下载地址:http://download.csdn.net/detail/yu422560654/3905368

 主要的BusinessService.java

package mypack;

import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import java.util.*;

public class BusinessService{
  public static SessionFactory sessionFactory;
  static{
     try{
       Configuration config = new Configuration()
             .setNamingStrategy( new MyNamingStrategy() )
             .configure();       //加载hibernate.cfg.xml文件中配置的信息
      sessionFactory = config.buildSessionFactory();
    }catch(RuntimeException e){e.printStackTrace();throw e;}
  }

  public Customer loadCustomer(long customer_id){
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      Customer customer=(Customer)session.get(Customer.class,new Long(customer_id));
      tx.commit();
      return customer;
    }catch (RuntimeException e) {
      if (tx != null) {
         tx.rollback();
      }
      throw e;
    } finally {
       session.close();
    }
  }

  public void saveCustomer(Customer customer){
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      session.save(customer);
      tx.commit();

    }catch (RuntimeException e) {
      if (tx != null) {
         tx.rollback();
      }
      throw e;
    } finally {
       session.close();
    }
  }

    public void loadAndUpdateCustomer(long customerId) {
      Session session = sessionFactory.openSession();
      Transaction tx = null;
      try {
        tx = session.beginTransaction();
        Customer customer=(Customer)session.get(Customer.class,new Long(customerId));
        customer.setDescription("A lovely customer!");
        tx.commit();

    }catch (RuntimeException e) {
      if (tx != null) {
        tx.rollback();
      }
      throw e;
    } finally {
      session.close();
    }
  }

  public void updateCustomer(Customer customer){
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      session.update(customer);
      tx.commit();

    }catch (RuntimeException e) {
      if (tx != null) {
         tx.rollback();
      }
      throw e;
    } finally {
       session.close();
    }
  }

  public void saveDictionary(Dictionary dictionary) {
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      session.save(dictionary);
      tx.commit();

    }catch (RuntimeException e) {
      if (tx != null) {
        tx.rollback();
      }
      throw e;
    } finally {
      session.close();
    }
  }

 public void updateDictionary(Dictionary dictionary){
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      session.update(dictionary);
      tx.commit();

    }catch (RuntimeException e) {
      if (tx != null) {
        tx.rollback();
      }
      throw e;
    } finally {
      session.close();
    }
  }
  public Dictionary loadDictionary(long dictionary_id) {
    Session session = sessionFactory.openSession();
    Transaction tx = null;
    try {
      tx = session.beginTransaction();
      Dictionary dictionary=(Dictionary)session.get(Dictionary.class,new Long(dictionary_id));
      tx.commit();
      return dictionary;
    }catch (RuntimeException e) {
      if (tx != null) {
        tx.rollback();
      }
      throw e;
    } finally {
      session.close();
    }
  }

  public void printCustomer(Customer customer){
      System.out.println("name:"+customer.getName());
      System.out.println("sex:"+customer.getSex());
      System.out.println("description:"+customer.getDescription());
      System.out.println("avgPrice:"+customer.getAvgPrice());
      System.out.println("totalPrice:"+customer.getTotalPrice());
  }

  public void printDictionary(Dictionary dictionary){
      System.out.println("type:"+dictionary.getType());
      System.out.println("key:"+dictionary.getKey());
      System.out.println("value:"+dictionary.getValue());
  }
   public void test(){
      Customer customer=new Customer("Laosan","Zhang",'M',new HashSet(),"A good citizen!");
      Order order1=new Order("Order001",new Double(100),customer);
      Order order2=new Order("Order002",new Double(200),customer);
      customer.getOrders().add(order1);
      customer.getOrders().add(order2);

      saveCustomer(customer);

      customer=new Customer("Laowu","Wang",'M',new HashSet(),null);
      saveCustomer(customer);

      customer=loadCustomer(1);
      printCustomer(customer);

      customer.setDescription("An honest customer!");
      updateCustomer(customer);

      loadAndUpdateCustomer(1);

      Dictionary dictionary=new Dictionary("SEX","M","MALE");
      saveDictionary(dictionary);

      dictionary=loadDictionary(1);
      dictionary.setValue("MAN");
      updateDictionary(dictionary);

      dictionary=loadDictionary(1);
      printDictionary(dictionary);

   }

  public static void main(String args[]) {
    new BusinessService().test();
    sessionFactory.close();
  }
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值