原创

JPA不更新值为null的解决方案&&JPA优雅的更新

关于@DynamicUpdate注解

使用@DynamicUpdate注解,通过在Entity实体类上添加此注解,再结合repository.save()方法进行字段更新,此方法的确具有可行性,但是仍存在一个问题:当字段值为null值时,Jpa会将null值与原值作比较,如果原值不为null,那么原值将会被覆盖为null

解决办法 - JpaUtil

写一个JpaUtil工具类避免空值对于动态部分更新的影响,配合@DynamicUpdate一起使用。

核心就是使用的Spring的BeanUtils

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapperImpl;

import java.beans.PropertyDescriptor;
import java.util.stream.Stream;

/**
 * JPA避免一些空值对于动态部分更新的影响工具类
 * 
 * @author Zhaopo Liu
 */
public class JpaUtil {

    /**
     * 查询出entity值 -> JpaUtil.copyNotNullProperties(input, entity); -> save(entity)
     * 
     * @param input 输入实体类
     * @param entity 数据库查询出的实体类
     */
    public static void copyNotNullProperties(Object input, Object entity) {
        BeanUtils.copyProperties(input, entity, getNullPropertyNames(input));
    }

    /**
     * 忽略的字段:值为null、浮点数为0.0、值为空字符串""
     * 
     * ignoreProperties {@link BeanUtils#copyProperties(java.lang.Object, java.lang.Object, java.lang.String...)}
     * 
     * @param object 传入全部字段
     * @return 忽略的字段
     */
    private static String[] getNullPropertyNames(Object object) {
        final BeanWrapperImpl wrapper = new BeanWrapperImpl(object);
        return Stream.of(wrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName)
            .filter(propertyName -> wrapper.getPropertyValue(propertyName) == null
                || "0.0".equals(String.valueOf(wrapper.getPropertyValue(propertyName)))
                || "".equals(String.valueOf(wrapper.getPropertyValue(propertyName))))
            .toArray(String[]::new);
    }

}

使用demo:

这种方式比较优雅,避免了你写很多setXXX(...),省去了很多代码,让你的代码更具有可读性。

@Transactional(rollbackFor = Exception.class)
public IronFastenersInsulationTask createOrUpdate(IronFastenersInsulationTask insulationTask) {
    return Optional.of(ironFastenersInsulationTaskRepository.findByIdOrTaskId(insulationTask.getTaskId())
                       .orElseGet(() -> ironFastenersInsulationTaskRepository.save(insulationTask))).map(entity -> {

        // 使用JpaUtil优雅的写法
        JpaUtil.copyNotNullProperties(insulationTask, entity);

        // 不优雅的写法
        // entity.setRemark(insulationTask.getRemark());
        // entity.setTestTemperature(insulationTask.getTestTemperature());
        // entity.setHumidity(insulationTask.getHumidity());
        // entity.setTestDeviceName(insulationTask.getTestDeviceName());
        // entity.setIronGround(insulationTask.getIronGround());
        // entity.setClipGround(insulationTask.getClipGround());
        // entity.setIronClip(insulationTask.getIronClip());
        // return ironFastenersInsulationTaskRepository.save(entity);

        return ironFastenersInsulationTaskRepository.save(entity);
    }).orElseGet(() -> ironFastenersInsulationTaskRepository.save(insulationTask));
}

核心就是使用Spring的BeanUtilscopyProperties方法,里面有一个ignoreProperties是指忽略拷贝的字段:

public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
    copyProperties(source, target, (Class)null, ignoreProperties);
}
正文到此结束
本文目录