更新实体只更新非空字段

Posted deleba

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了更新实体只更新非空字段相关的知识,希望对你有一定的参考价值。

更新实体的时候,经常会获取整个实体对数据库进行更新,但是前端传回的实体可能是不完整的,某些空字段是不需要更新,这样会造成数据不完整,需要过滤出非空字段进行更新
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));
   }
}

  



以上是关于更新实体只更新非空字段的主要内容,如果未能解决你的问题,请参考以下文章

指定为非空的参数为空:无法更新 Spring Boot jpa 中的单个实体字段。导致指定为非空的参数为空

非空约束对数据更新的影响

Spring Mongo 仅通过新 POJO 的非空字段进行更新

sql中更新某个字段中部分空值的语句怎样写?

从大表中选择非空字段

MyBatis-Plus使用学习