Spring Data Jpa Null属性更新解决方案

背景

使用Spring Data Jpa来操作数据库在更新数据的时候发现一个问题,属性值为Null竟然也更新,这就会导致本来没有更新的属性值,全部就成了Null。详细点说就是前端传来一个实体对应的Json串,映射成对应的实体后,因为属性有所缺失,导致对象里有Null值,直接用来更新数据库的话,就会将原本的属性给替换掉。

原因

经过各种操作,得知 :Jpa不知道你是想把属性设置为Null,还是不想。所以没有进行这方面的设计,强烈希望Jpa的接口会做出这方面的扩充,那怕多一个表征是否设置Null的参数呢,当然要是提供一个修改属性的列表做参数就更好了。

实践

好多人用这个注解来解决这个问题,@DynamicUpdate,实际上他们都误解了这个注解的意思:只更新我们修改过的字段。

这个意思是你提交的实体和数据库里的实体如果有点属性值是一样的就不必更新那个属性了,所谓修改过的字段比较的是数据库的实体你提交到数据库的实体。

好多人把这个功能错误的以为是只改从前端传入的数据,实际上你传入的json映射成实体的时候,缺失的属性全部置null了。这和数据库里对应字段存的不一致的时候,自然还是会改变的。

实体:

package com.school.stu_system.domain;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jdk.nashorn.internal.objects.annotations.Getter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import java.io.Serializable;
import java.util.List;
import java.util.Set;

/**
 * @program: stu_system
 * @description:
 * @author: William Munch
 * @create: 2019-07-09 16:16
 **/
@Entity
@Table(name = "t_course")
@JsonIgnoreProperties(value = { "hibernateLazyInitializer", "handler" })

public class Course  implements Serializable {

    private static final long serialVersionUID = -4310210227936391905L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="course_id")
    private Integer id;

    @Column(length = 100,name="course_name",nullable = false)
    private String name;

    //双向多对多
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "t_student_course",
            joinColumns = @JoinColumn(name="course_id",referencedColumnName="course_id"),
            inverseJoinColumns = @JoinColumn(name="student_id",referencedColumnName="student_id"))
    @JsonIgnore
    private Set<Student> students;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

加入一个工具类

package com.school.stu_system.util;
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;

/**
 * @program: stu_system
 * @description: 处理  更新实体时提交实体的null赋值问题
 * @author: William Munch
 * @create: 2019-07-10 15:36
 **/
public class UpdateUtil {
/**
 * 将目标源中不为空的字段过滤,将数据库中查出的数据源复制到提交的目标源中
 *
 * @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<String> 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);
    }
}

service层的代码:

    public Course updateCourse(Course course)
    {
        Optional<Course> course_op = courseDao.findById(course.getId());
        if(course_op.isPresent())
        {
            UpdateUtil.copyNullProperties(course_op.get(), course);
            return courseDao.saveAndFlush(course);
        }
        else{
            throw new MyRuntimeException(MyResponseEnums.NO_RECORD);

        }
    }

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值