更新實體的時候,經常會獲取整個實體對數據庫進行更新,但是前端傳回的實體可能是不完整的,某些空字段是不需要更新,這樣會造成數據不完整,需要過濾出非空字段進行更新
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));
}
}
