昨天搜了很多资料,发现都没有很好解决hibernate更新部分字段的方法,因为我们用到的都是saveOrUpdate方法,这个方法,它会更新对象的所有字段,会造成很大的麻烦。比如有一个User对象,它有20个字段,但在修改用户的表单里,通过name="user.xx"传到action中只有10个,我们要修改的只要这10个,另外剩下的10个比如注册时间等字段不修改,我们通过debug会发现,这些不修改的字段,在传到action的vo里是null,于是傻乎乎的调用了hibernate的saveOrUpdate方法,导致po的字段为null了,原因在于传到action的vo,不修改的字段值为空,而hibernate的saveOrUpdate方法会更新所有字段。
我有个很好的方法,重写Spring框架的BeanUtils类的copyProperties(Object source, Object target)方法,代码如下:
/**
* 重写--防止实际使用中null覆盖有效value的问题
*
*/
public abstract class CommonBeanUtils extends org.springframework.beans.BeanUtils {
public static void copyProperties(Object source, Object target) throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
for (PropertyDescriptor targetPd : targetPds) {
if (targetPd.getWriteMethod() != null) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null && sourcePd.getReadMethod() != null) {
try {
Method readMethod = sourcePd.getReadMethod();
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
// 这里判断以下value是否为空 当然这里也能进行一些特殊要求的处理 例如绑定时格式转换等等
if (value != null) {
Method writeMethod = targetPd.getWriteMethod();
Type targetParameterType = writeMethod.getGenericParameterTypes()[0];
//特殊类型不再执行copy XMLGregorianCalendar
if(!(targetParameterType.equals(XMLGregorianCalendar.class))){
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
}
} catch (Throwable ex) {
throw new FatalBeanException("Could not copy properties from source to target", ex);
}
}
}
}
}
}
source参数是源对象,在修改用户这一操作里,source就是我们JSP页面传来的vo对象,target是被赋值字段属性值的PO对象,我们只要把PO从数据库里读取出来,将VO赋值给PO就好了。
当vo中那些不修改的字段为null时,这个方法是不拷贝null的字段的,这么一来,注册时间在vo里是空的,就不会覆盖PO中有值的注册时间。我们最后只要将po更新到数据库就好了。