java date赋空值_详解Spring Data Jpa当属性为Null也更新的完美解决方案

开场白

我本来是一名android开发者,突然就对java后端产生了浓烈的兴趣。所以,立马就转到了后端。第一个项目使用的使用Spring Data Jpa来操作数据库的,可是在更新数据的时候发现一个问题,属性值为Null竟然也更新,这就会导致本来没有更新的属性值,全部就成了Null。

原因

经过一番度娘操作,原来Jpa,不知道你是想把属性设置为Null,还是不想。

解决方法

找到一个方法,就是在数据模型上加上注解@DynamicUpdate,可是发现并不好使。而后经过整理,找到以下解决方案

我们有如下实体

@Entity

public class User{

public User(){

}

@Id

@GeneratedValue

public Long id;

private String name;

private String mobileNo;

private String email;

private String password;

private Integer type;

private Date registerTime;

private String region;

private Integer validity;

setter...

getter...

}

需求:我们只更新用户的名字,其他属性值不变。

controller代码如下

@RestController

public class UserController {

@Autowired

private UserDao userDao;

@PostMapping(value = "/save")

public String save(@RequestBody User u) {

userDao.save(u)

return "更新成功";

}

}

注意:如果我们只是更新用户的名字,我们会这样操作,如下只是提交需要更新的用户的id和需要更新属性的值,但是这样的结果就是,其他没有提交更改的属性值,会被当成Null,将数据库中对应值全部设为Null,为了解决这个问题提出以下方案。

{

"id" : "1",

"name" : "张三"

}

方案如下:

说明:

目标源:请求更新的实体数据。

数据源:通过目标源传上来的id,去数据库中查出的实体数据

我们可以将目标源中需要改变的属性值过滤掉以后,将数据源中的数据复制到目标源中,这样就达到了,只是更新需要改变的属性值,不需要更新的保持不变。

工具类如下

import org.springframework.beans.BeanUtils;

import org.springframework.beans.BeanWrapper;

import org.springframework.beans.BeanWrapperImpl;

import java.beans.PropertyDescriptor;

import java.util.HashSet;

import java.util.Set;

/**

* There is no royal road to learning.

* Description:提交实体对象中的null赋值

* Created by 贤领·周 on 2018年04月10日 15:26

*/

public class UpdateTool {

/**

* 将目标源中不为空的字段过滤,将数据库中查出的数据源复制到提交的目标源中

*

* @param source 用id从数据库中查出来的数据源

* @param target 提交的实体,目标源

*/

public static void copyNullProperties(Object source, Object target) {

BeanUtils.copyProperties(source, target, getNoNullProperties(target));

}

/**

* @param target 目标源数据

* @return 将目标源中不为空的字段取出

*/

private static String[] getNoNullProperties(Object target) {

BeanWrapper srcBean = new BeanWrapperImpl(target);

PropertyDescriptor[] pds = srcBean.getPropertyDescriptors();

Set noEmptyName = new HashSet<>();

for (PropertyDescriptor p : pds) {

Object value = srcBean.getPropertyValue(p.getName());

if (value != null) noEmptyName.add(p.getName());

}

String[] result = new String[noEmptyName.size()];

return noEmptyName.toArray(result);

}

}

这里重点说明一下, BeanUtils.copyProperties这个方法,网上很多教程都是存在误区的,源码如下:

/**

* 通过源码不难看出,该方法就是将source的属性值复制到target中

*

* @param source 数据源(也就是我们通过id去数据库查询出来的数据)

* @param target 目标源(也就是我们请求更新的数据)

* @param ignoreProperties (需要过滤的字段)

*/

public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {

copyProperties(source, target, (Class)null, ignoreProperties);

}

private static void copyProperties(Object source, Object target, Class> editable, String... ignoreProperties) throws BeansException {

Assert.notNull(source, "Source must not be null");

Assert.notNull(target, "Target must not be null");

Class> actualEditable = target.getClass();

if (editable != null) {

if (!editable.isInstance(target)) {

throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");

}

actualEditable = editable;

}

PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);

List ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;

PropertyDescriptor[] var7 = targetPds;

int var8 = targetPds.length;

for(int var9 = 0; var9 < var8; ++var9) {

PropertyDescriptor targetPd = var7[var9];

Method writeMethod = targetPd.getWriteMethod();

if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {

PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());

if (sourcePd != null) {

Method readMethod = sourcePd.getReadMethod();

if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {

try {

if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {

readMethod.setAccessible(true);

}

Object value = readMethod.invoke(source);

if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {

writeMethod.setAccessible(true);

}

writeMethod.invoke(target, value);

} catch (Throwable var15) {

throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);

}

}

}

}

}

}

有了上面的工具类以后,我们的controller如下写:

@RestController

public class UserController {

@Autowired

private UserDao userDao;

@PostMapping(value = "/save")

public String save(@RequestBody User u) {

if(u.getId != 0){

User source= userDao.findOne(u.getId);

UpdateTool.copyNullProperties(source, u);

}

userDao.save(u)

return "更新成功";

}

}

结果

这样我们更新部分属性值得时候,其他不更新的属性值就不会设置为Null

{

"id" : "1",

"name" : "张三"

}

性能上肯定是有影响,但是目前整理可行的方案,如果有更好的解决方案欢迎留言。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值