Hibernate二次笔记 之 从one-to-many分析处理技巧

本文探讨了在不增加冗余字段的前提下,如何计算客户的订单总额和平均价格。提供了两种解决方案:一是通过编程逻辑进行计算;二是利用Hibernate映射文件中的formula属性自动计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里用最常见的例子:Customer和Order来举例

客户和订单。

一个客户可能有N个订单,Customer和Order两个类分别对应两个表,字段中有各自相应属性...如Customer表里的id、name..Order表里的id,number,pricec_id..这些必要的属性外。当出现一种情况是业务需要某一用户的订单总金额(totalprice)和平均金额(avgprice)的时,该去怎么处理。

假设在Customer里面再加入两个字段的话,问题可以解决,但并不合理:因为数据在经常变动的情况下,双表关联频繁update显然会影响软件的性能,如果放在表中,这两个字段可视为是冗余数据

那么我们现在就不做一一对应的关系,只在类中有这两个属性,表中没有。利用已知的条件:每个order的金额、和用户的order数来在程序中求出总金额与平均金额;

有两种方法来处理这样的功能,一种通常的方法是在程序中写一处理方法:

import java.io.Serializable;
import java.util.*;

public class Customer {

    
private Long id;
    
private String firstname;
    
private String lastname;
    
private char sex;
    
private Set orders = new HashSet();
    
private double avgPrice;
    
private double totalPrice;
    
private String description;

    
public Customer() {
    }

    
public Customer(String firstname, String lastname, char sex, Set orders,
                    String description) {
        
this.firstname = firstname;
        
this.lastname = lastname;
        
this.sex = sex;
        
this.orders = orders;
        
this.description = description;
    }

    
public Long getId() {
        
return this.id;
    }

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

    
public String getFirstname() {
        
return firstname;
    }

    
public void setFirstname(String firstname) {
        
this.firstname = firstname;
    }

    
public String getLastname() {
        
return lastname;
    }

    
public void setLastname(String lastname) {
        
this.lastname = lastname;
    }

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

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

    
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(); 
//或者通过 <property>的 formula 属性来实现
    }

    
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
++
;
            }
            
// Set the price for the order from the calcualted value

            avgPrice = totalPrice / count;
            setAvgPrice(avgPrice);
        }
    }

    
public char getSex() {
        
return this.sex;
    }

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

    
public String getDescription() {
        
return this.description;
    }

    
public void setDescription(String description) {
        
this.description = description;
    }

    
public boolean equals(Object lObj) {
        
if (this == lObj) {
            
return true//比较的是两个对象的引用(references)是否相等
        }
        
if (lObj == null) {
            
return false//检查 lObj是否为空
        }
        
if (getClass() != lObj.getClass()) {
            
return false//检查是否属于同一个class
        }
        
return true;
    }

}

可以看出,用calculatePrice()方法 来运算可以解决这样的问题的。

下面的一种方法是通过映射文件来解决此问题,如果从SQL语句上来讲,avgPrice和totalPrice分别都可以用SQL语句来查出。如下:

select  sum(o.PRICE)  from ORDERS  o where o.CUSTOMER_ID=?

select  avg(o.PRICE)  from ORDERS  o where o.CUSTOMER_ID=?

而hibernate的映射文件支持方程式formula,我们可以在Customer.hbm.xml里面这么写:

    ...
    
<property name="totalPrice" 
       formula
="(select  sum(o.PRICE)  from ORDERS  o where o.CUSTOMER_ID=ID)" />
       
   
<property name="avgPrice" 
       formula
="(select  avg(o.PRICE)  from ORDERS  o where o.CUSTOMER_ID=ID)" />
   
<property name="description"  type="text" column="DESCRIPTION"/>

再通过类里面的get、set方法来取得avgPrice和totalPrice。

 

总结,咋一看来,好像第二种方法比第一种方法要简练。但仔细想,现在我用的是SQL Server,如果底层数据库变了的话,而映射文件里的方程式恰好又有相关联的数据库函数的话,那么就违背了"write once,run anywhere"的原则,而第一种逻辑运算则变成了真理。除非没有了Java.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值