每天都会通过Web服务导入数据。
我知道我可以遍历pojos上的所有字段,并检查null值,并在适当的地方进行更新,但是我更愿意让hibernate做到这一点,因为这样做会减少我添加字段和忘记将其添加到此手动合并过程中。
hibernate状态可以执行上面的步骤4吗?
不,Hibernate(或JPA)没有提供现成的功能,但是使用JavaBeans机制(或在其之上提供抽象层的许多库之一)并不难实现。
这是一种方法,该方法使用标准JavaBeans 机制从中复制所有属性到beanA,beanB如果它们为null :beanBIntrospector
beanA
beanB
Introspector
public static void copyBeanProperties( final Object beanA, final Object beanB){ if(beanA.getClass() != beanB.getClass()){ // actually, this may be a problem, because beanB may be a // cglib-created subclass throw new IllegalArgumentException(); } try{ for( final PropertyDescriptor pd : Introspector .getBeanInfo(beanB.getClass(), Object.class) .getPropertyDescriptors()){ if(pd.getReadMethod().invoke(beanB)==null){ pd.getWriteMethod().invoke(beanB, pd.getReadMethod().invoke(beanA) ); } } } catch(IntrospectionException e){ throw new IllegalStateException(e); } catch(IllegalAccessException e){ throw new IllegalStateException(e); } catch(InvocationTargetException e){ throw new IllegalStateException(e); } }
当然,这只是一个快速而肮脏的实现,但这应该可以帮助您入门。
这是一个使用Commons / BeanUtils的优雅版本。它隐藏了您的反射,并提供基于地图的属性访问:
public static void copyBeanProperties(final Object beanA, final Object beanB){ try{ @SuppressWarnings("unchecked") // this should be safe final Map<String, Object> beanAProps = PropertyUtils.describe(beanA); @SuppressWarnings("unchecked") // this should be safe final Map<String, Object> beanBProps = PropertyUtils.describe(beanB); if(!beanAProps.keySet().containsAll(beanBProps.keySet())){ throw new IllegalArgumentException("Incompatible types: " + beanA + ", " + beanB); } for(final Entry<String, Object> entryA : beanAProps.entrySet()){ if(beanBProps.get(entryA.getKey()) == null){ PropertyUtils.setMappedProperty(beanB, entryA.getKey(), entryA.getValue()); } } } catch(final IllegalAccessException e){ throw new IllegalStateException(e); } catch(final InvocationTargetException e){ throw new IllegalStateException(e); } catch(final NoSuchMethodException e){ throw new IllegalStateException(e); } }
这是使用Spring BeanWrapper接口的另一个版本(最不冗长,因为Spring在所有反射之上都提供了抽象,并且它是自己的异常处理),但是不幸的BeanWrapper是,该技术仅适用于Spring IOC容器(当然,如果您不使用容器):
BeanWrapper
public static void copyBeanProperties(final Object beanA, final Object beanB){ final BeanWrapper wrapperA = new BeanWrapperImpl(beanA); final BeanWrapper wrapperB = new BeanWrapperImpl(beanB); try{ for(final PropertyDescriptor descriptor : wrapperB .getPropertyDescriptors()){ final String propertyName = descriptor.getName(); if(wrapperB.getPropertyValue(propertyName) == null){ wrapperB.setPropertyValue(propertyName, wrapperA.getPropertyValue(propertyName)); } } } catch(final /* unchecked */ InvalidPropertyException e){ throw new IllegalArgumentException("Incompatible types: " + beanA + ", " + beanB, e); } }