Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

更新实体只更新非空字段

Delaba 2019-01-27 17:06:00 阅读数:142 评论数:0 点赞数:0 收藏数:0

更新实体的时候,经常会获取整个实体对数据库进行更新,但是前端传回的实体可能是不完整的,某些空字段是不需要更新,这样会造成数据不完整,需要过滤出非空字段进行更新
1.首先要写好基类
其中基类中要有获取主键的方法。
 1 //基类中获取字段的发方法
 2
 3 private void getField(Class clazz, List<Field> list) {
 4 if (!clazz.isInstance(SuperVO.class)) {
 5 Field[] fields = clazz.getDeclaredFields();
 6 if (fields != null && fields.length > 0) {
 7 Field[] arg3 = fields;
 8 int arg4 = fields.length;
 9
10 for (int arg5 = 0; arg5 < arg4; ++arg5) {
11 Field field = arg3[arg5];
12  list.add(field);
13  }
14  }
15
16 this.getField(clazz.getSuperclass(), list);
17  }
18 }
 1 //获取实体主键
 2 @JsonIgnore
 3 public String getPrimaryKey() throws BusinessException {
 4 ArrayList fields = new ArrayList();
 5 this.getField(this.getClass(), fields);
 6 Iterator arg1 = fields.iterator();
 7
 8  Field field;
 9 do {
10 if (!arg1.hasNext()) {
11 throw new BusinessException("获取主键失败:未找到主键注解字段");
12  }
13
14 field = (Field) arg1.next();
15 } while (field.getAnnotation(Id.class) == null);
16
17 try {
18 return BeanUtils.getProperty(this, field.getName());
19 } catch (Exception arg4) {
20 LoggerFactory.getLogger(this.getClass()).error(arg4.getMessage(), arg4);
21 throw new BusinessException("获取主键失败", arg4);
22  }
23 }

 

2.可以建立一个公共接口,实现更新方法先根据主键查询数据库实体

 1 public abstract class AbstractBaseService<T extends SuperVO> {
 2
 3 protected abstract CrudRepository<T, String> getRepository();
 4
 5  @Transactional
 6 public T update(T vo) throws BusinessException {
 7 List vos = (List) this.update((Iterable) Arrays.asList(new SuperVO[]{vo}));
 8 return (SuperVO) vos.get(0);
 9  }
10
11  @Transactional
12 public Iterable<T> update(Iterable<T> vos) throws BusinessException {
13 vos.forEach((vo) -> {
14 T dbVo = this.getRepository().findOne(vo.getPrimaryKey());
15  UpdateUtil.copyPropertiesIgnoreNull(dbVo,vo);
16  });
17 return this.save(vos);
18  }
19 }

这里有一个隐藏性能问题,影响比较大,循环中频繁操作查询数据库,是不合理的,这部分可以修改为批量获取主键集合,查询出所有要更新实体,再进行替换空值,进行更新。

 1 @Transactional
 2 public Iterable<T> update(Iterable<T> vos) throws BusinessException {
 3 List<String> ids = StreamSupport.stream(vos.spliterator(), false).stream().map(T::getPrimaryKey).collect(Collectors.toList());
 4 Iterable<T> dbVos = this.getRepository().findAll(ids);
 5 Map<String, T> dbMap = StreamSupport.stream(dbVos.spliterator(), false).stream().collect(Collectors.toMap(T::getPrimaryKey, t->t));
 6 vos.forEach((vo) -> {
 7  UpdateUtil.copyPropertiesIgnoreNull(dbMap.get(vo.getPrimaryKey()),vo);
 8  });
 9 return this.save(vos);
10 }

 

3.updateUtil

获取前端实体保存入库前,可以使用,该方法过滤掉空值,再进行更新

需要注意的是,这个方法之前是要建立好基类

import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
/**
* update更新非空实体
*
* @author Administrator
*
*/
public class UpdateUtil {
/**
* 获取目标对象中不为空的字段
*
* @param source
* @return
*/
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);
}
/**
* 复制源对象到目标对象,忽略目标对象不为空的字段
*
* @param src
* @param target
*/
public static void copyPropertiesIgnoreNull(Object src, Object target) {
BeanUtils.copyProperties(src, target, getNullPropertyNames(target));
}
}

版权声明
本文为[Delaba]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/deleba/p/10327315.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领