jpa中为null不更新实现的几种方式
- ps : 以下几种是StackOverflow等收集过来的方法,但是测试还是有问题(没有全部测试过,有空处理)
BeanUtils的使用
- 目前BeanUtils还没有支持为空则不进行拷贝,但是有一个方法copyProperties(Object source, Object target, String… ignoreProperties)可以忽略部分值不进行拷贝,我们将需要忽略的值放入String数组中即可。(但在使用时还是存在问题,debug后还没解决,目前没有时间解决,ok的朋友可以告诉我)
- 使用方法如下
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
// then use Spring BeanUtils to copy and ignore null
public static void myCopyProperties(Object src, Object target) {
BeanUtils.copyProperties(src, target, getNullPropertyNames(src))
}
其中java8可以采取一些方式
public static String[] getNullPropertyNames(Object source) {
final BeanWrapper wrappedSource = new BeanWrapperImpl(source);
return Stream.of(wrappedSource.getPropertyDescriptors())
.map(FeatureDescriptor::getName)
.filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null)
.toArray(String[]::new);
}
我们查看BeanUtils的源码可以发现,理论上应该时可以的
public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
copyProperties(source, target, (Class)null, ignoreProperties);
}
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
PropertyDescriptor[] var7 = targetPds;
int var8 = targetPds.length;
for(int var9 = 0; var9 < var8; ++var9) {
PropertyDescriptor targetPd = var7[var9];
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
} catch (Throwable var15) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
}
}
}
}
}
}
当条件 writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName())) 成立的时候则不进行拷贝,其中ignoreList是我们传入的数据。
注解解决@DynamicUpdate
- @DynamicUpdate 与 @DynamicInsert 都是参数为空的不进行更新或者插入,需要将默认值value置为true(默认为true,但是不同版本可能不一样,可点进源码查看一下)
自己写一个反射
- 则里就不给出方式了,思路大概是先查出需要修改的对象和需要修改的对象进行比较。通过反射,将新的对象中全部的参数获取出来(也可以通过get set方法,但是没必要)进行判断,如果为null,则进行赋值。
修改源码
- 个人感觉没必要,也是基于上面第一第三两种方式进行修改,需要的可以参考这篇博客 https://www.jianshu.com/p/4931fbc52ea1