假定Customer类有一个avgPrice属生, 表示这个客户的所有订单的平均价格. 它的取值为与它关联的所有Order对象的price的平均值. 在CUSTOMERS表中没有 avg_price字段. 可以在Customer类的setOrders()方法中加入程序逻辑来实现:
private Set orders = new HashSet(0);
private double avgPrice;
public double getAvgPrice() {
return this.avgPrice;
}
private void setAvgPrice(double avgPrice) {
this.avgPrice = avgPrice;
}
public void setOrders(Set orders) {
this.orders = orders;
calculatePrice();
}
public Set getOrders() {
return orders;
}
private void calculatePrice() {
double avgPrice = 0.0;
double totalPrice = 0.0;
int count = 0;
if(getOrders() != null ) {
Iterator iter = getOrders().iterator();
while( iter.hasNext() ) {
double orderPrice = ((Order))iter.next()).getPrice();
totalPrice += orderPrice;
count++;
}
avgPrice = totalPrice/count;
setAvgPrice(avgPrice);
}
}
Customer类的getAvgPrice()方法为public类型, 而setAvgPrice()方法为private类型, 因此JAVA应用程序只能读取avgPrice属生, 但是不能直接修改avgPrice属性. 当JAVA应用程序或者Hibernate调用setOrders()方法时, 会自动调用calculatePrice()方法, calculatePrice()方法又调用setAvgPrice()方法, 从而给avgPrice属性赋值. 由此可见, 如果希望把为持久属性表示客户的所有订单的价格总和, 它的取值为与Customer对象关联的所有Order对象的price属性值的和. 在CUSTOMERS表中没有对应的TOTAL_PRICE字段.在Customer.xml文件中映射totalPrice属性的代码如下:
<property name="totalPrice" formula="(select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID = ID)" />
当Hibernate从数据库中查询Customer对象时, 在select语句中会包含以上用于计算totalPrice派生属性的子查询语句:
select ID, NAME, SEX, 'CUSTOMER DESCRIPTION', (select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=1) from customers;
如果子查询语句的查询结果为空, Hibernate会把totalPrice属性赋值为NULL, 如果totalPrice属性为double或int等基本类型, 会抛出异常:
[java] org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of 包名
为了避免以上异常, 应该把totalPrice属性定义为Double或Integer等包装类型.
<property>元素的formula属性指定一个SQL表达式, 该表达式可以引用表的字段, 调用SQL函数或者包含子查询语句. 例如LineItem类中有一个unitPrice属性, 而在LINEITEMS表中没有对应的UNIT_PRICE字段,可以通过以下方式映射unitPrice属性:
<property name="unitPrice" formula="BASE_PRICE*QUANTITY" />