<hibernate-mapping >
<class name="mypack.SalariedEmployee" table="SALARIED_EMPLOYEES">
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="name" type="string" column="NAME" />
<property name="salary" column="SALARY" type="double" />
<many-to-one
name="company"
column="COMPANY_ID"
class="mypack.Company"
/>
</class>
</hibernate-mapping>
由於Employee類沒有相應的映射文件,因此在初始化Hibernate時,只需向Configuration對象中加入Company類、HourlyEmployee類和SalariedEmployee類:
Configuration config = new Configuration();
config.addClass(Company.class)
.addClass(HourlyEmployee.class)
.addClass(SalariedEmployee.class);
14.1.2 操縱持久化對象
這種映射方式不支持多態查詢,在本書第11章的11.1.6節(多態查詢)介紹了多態查詢的概念。對於以下查詢語句:
List employees=session.find("from Employee");
如果Employee類是抽象類,那麼Hibernate會拋出異常。如果Employee類是具體類,那麼Hibernate僅僅查詢EMPLOYEES表,檢索出Employee類本身的實例,但不會檢索出它的兩個子類的實例。本節的范例程序位於配套光盤的sourcecode\chapter14\14.1目錄下,運行該程序前,需要在SAMPLEDB數據庫中手工創建COMPANIES表、HE表和SE表,然後加入測試數據,相關的SQL腳本文件為\14.1\schema/sampledb.sql。
在chapter14目錄下有四個ANT的工程文件,分別為build1.xml、build2.xml、build3.xml和build4.xml,它們的區別在於文件開頭設置的路徑不一樣,例如在build1.xml文件中設置了以下路徑:
<property name="source.root" value="14.1/src"/>
<property name="class.root" value="14.1/classes"/>
<property name="lib.dir" value="lib"/>
<property name="schema.dir" value="14.1/schema"/>
在DOS命令行下進入chapter14根目錄,然後輸入命令:
ant -file build1.xml run
就會運行BusinessService類。ANT命令的-file選項用於顯式指定工程文件。BusinessService類用於演示操縱Employee類的對象的方法,例程14-4是它的源程序。
例程14-4 BusinessService.java
public class BusinessService{
public static SessionFactory sessionFactory;
static{
try{
Configuration config = new Configuration();
config.addClass(Company.class)
.addClass(HourlyEmployee.class)
.addClass(SalariedEmployee.class);
sessionFactory = config.buildSessionFactory();
}catch(Exception e){e.printStackTrace();}
}
public void saveEmployee(Employee employee) throws Exception{……}
public List findAllEmployees() throws Exception{……}
public Company loadCompany(long id) throws Exception{……}
public void test() throws Exception{
List employees=findAllEmployees();
printAllEmployees(employees.iterator());
Company company=loadCompany(1);
printAllEmployees(company.getEmployees().iterator());
Employee employee=new HourlyEmployee("Mary",300,company);
saveEmployee(employee);
}
private void printAllEmployees(Iterator it){
while(it.hasNext()){
Employee e=(Employee)it.next();
if(e instanceof HourlyEmployee){
System.out.println(((HourlyEmployee)e).getRate());
}else
System.out.println(((SalariedEmployee)e).getSalary());
}
}
public static void main(String args[]) throws Exception {
new BusinessService().test();
sessionFactory.close();
}
}
BusinessService的main()方法調用test()方法,test()方法依次調用以下方法。
findAllEmployees():檢索數據庫中所有的Employee對象。
loadCompany():加載一個Company對象。
saveEmployee():保存一個Employee對象。
(1)運行findAllEmployees()方法,它的代碼如下:
List results=new ArrayList();
tx = session.beginTransaction();
List hourlyEmployees=session.find("from HourlyEmployee");
results.addAll(hourlyEmployees);
List salariedEmployees=session.find("from SalariedEmployee");
results.addAll(salariedEmployees);
tx.commit();
return results;
為了檢索所有的Employee對象,必須分別檢索所有的HourlyEmployee實例和SalariedEmployee實例,然後把它們合並到同一個集合中。在運行Session的第一個find()方法時,Hibernate執行以下select語句:
select * from HOURLY_EMPLOYEES;
select * from COMPANIES where ID=1;
從HourlyEmployee類到Company類不是多態關聯,在加載HourlyEmployee對象時,會同時加載與它關聯的Company對象。
在運行Session的第二個find()方法時,Hibernate執行以下select語句:
select * from SALARIED_EMPLOYEES;
從SalariedEmployee類到Company類不是多態關聯,在加載SalariedEmployee對象時,會同時加載與它關聯的Company對象。在本書提供的測試數據中,所有HourlyEmployee實例和SalariedEmployee實例都與OID為1的Company對象關聯,由於該Company對象已經被加載到內存中,所以Hibernate不再需要執行檢索該對象的select語句。
(2)運行loadCompany()方法,它的代碼如下:
tx = session.beginTransaction();
Company company=(Company)session.load(Company.class,new Long(id));
List hourlyEmployees=session.find("from HourlyEmployee h where h.company.id="+id);
company.getEmployees().addAll(hourlyEmployees);
List salariedEmployees=session.find("from SalariedEmployee s where s.company.id="+id);
company.getEmployees().addAll(salariedEmployees);
tx.commit();
return company;
由於這種映射方式不支持多態關聯,因此由Session的load()方法加載的Company對象的employees集合中不包含任何Employee對象。BusinessService類必須負責從數據庫中檢索出所有與Company對象關聯的HourlyEmployee對象以及SalariedEmployee對象,然後把它們加入到employees集合中。
(3)運行saveEmployee(Employee employee)方法,它的代碼如下:
tx = session.beginTransaction();
session.save(employee);
tx.commit();
在test()方法中,創建了一個HourlyEmployee實例,然後調用saveEmployee()方法保存這個實例:
Employee employee=new HourlyEmployee("Mary",300,company);
saveEmployee(employee);
Session的save()方法能判斷employee變量實際引用的實例的類型,如果employee變量引用HourlyEmployee實例,就向HE表插入一條記錄,執行如下insert語句:
insert into HOURLY_EMPLOYEES(ID,NAME,RATE,CUSTOMER_ID)
values(3, 'Mary',300,1);
如果employee變量引用SalariedEmployee實例,就向SE表插入一條記錄。