每天,数据通过网络服务导入。
我知道我可以遍历pojos上的所有字段,并检查空值,并在适当的地方进行更新,但我更愿意让hibernate执行此操作,如果它能够,因为它会减少我添加的机会一个字段,忘记将其添加到此手动合并过程。
休眠可以执行上面的第4步吗?
答案 0 :(得分:11)
不,Hibernate(或JPA)不提供开箱即用的功能,但使用JavaBeans机制(或许多提供抽象层的库之一)并不难实现。
这是一种方法,如果beanA
中的所有属性在beanB
中为空,则使用标准的JavaBeans Introspector
机制将其复制到beanB
:
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's BeanWrapper
interface的另一个版本(它是最简洁的,因为Spring在所有反射之上提供了一个抽象并且它自己进行了异常处理),但不幸的是BeanWrapper
技术仅适用于Spring IOC容器(当然,如果你不使用容器,这只是不幸的事情):
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);
}
}
答案 1 :(得分:0)
Hibernate不会为你做这件事。您可以更改setter
以获得此功能。