更新實體只更新非空欄位
更新實體的時候,經常會獲取整個實體對資料庫進行更新,但是前端傳回的實體可能是不完整的,某些空欄位是不需要更新,這樣會造成資料不完整,需要過濾出非空欄位進行更新 1.首先要寫好基類 其中基類中要有獲取主鍵的方法。
1 //基類中獲取欄位的發方法 2 3 private void getField(Class clazz, List<Field> list) { 4if (!clazz.isInstance(SuperVO.class)) { 5Field[] fields = clazz.getDeclaredFields(); 6if (fields != null && fields.length > 0) { 7Field[] arg3 = fields; 8int arg4 = fields.length; 9 10for (int arg5 = 0; arg5 < arg4; ++arg5) { 11Field field = arg3[arg5]; 12list.add(field); 13} 14} 15 16this.getField(clazz.getSuperclass(), list); 17} 18}
1 //獲取實體主鍵 2 @JsonIgnore 3public String getPrimaryKey() throws BusinessException { 4ArrayList fields = new ArrayList(); 5this.getField(this.getClass(), fields); 6Iterator arg1 = fields.iterator(); 7 8Field field; 9do { 10if (!arg1.hasNext()) { 11throw new BusinessException("獲取主鍵失敗:未找到主鍵註解欄位"); 12} 13 14field = (Field) arg1.next(); 15} while (field.getAnnotation(Id.class) == null); 16 17try { 18return BeanUtils.getProperty(this, field.getName()); 19} catch (Exception arg4) { 20LoggerFactory.getLogger(this.getClass()).error(arg4.getMessage(), arg4); 21throw new BusinessException("獲取主鍵失敗", arg4); 22} 23}
2.可以建立一個公共介面,實現更新方法先根據主鍵查詢資料庫實體
1 public abstract class AbstractBaseService<T extends SuperVO> { 2 3protected abstract CrudRepository<T, String> getRepository(); 4 5@Transactional 6public T update(T vo) throws BusinessException { 7List vos = (List) this.update((Iterable) Arrays.asList(new SuperVO[]{vo})); 8return (SuperVO) vos.get(0); 9} 10 11@Transactional 12public Iterable<T> update(Iterable<T> vos) throws BusinessException { 13vos.forEach((vo) -> { 14T dbVo = this.getRepository().findOne(vo.getPrimaryKey()); 15UpdateUtil.copyPropertiesIgnoreNull(dbVo,vo); 16}); 17return this.save(vos); 18} 19 }
這裡有一個隱藏效能問題,影響比較大,迴圈中頻繁操作查詢資料庫,是不合理的,這部分可以修改為批量獲取主鍵集合,查詢出所有要更新實體,再進行替換空值,進行更新。
1 @Transactional 2public Iterable<T> update(Iterable<T> vos) throws BusinessException { 3List<String> ids = StreamSupport.stream(vos.spliterator(), false).stream().map(T::getPrimaryKey).collect(Collectors.toList()); 4Iterable<T> dbVos = this.getRepository().findAll(ids); 5Map<String, T> dbMap = StreamSupport.stream(dbVos.spliterator(), false).stream().collect(Collectors.toMap(T::getPrimaryKey, t->t)); 6vos.forEach((vo) -> { 7UpdateUtil.copyPropertiesIgnoreNull(dbMap.get(vo.getPrimaryKey()),vo); 8}); 9return 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)); } }