使用 json 解析实体时休眠部分更新

2022-01-17 00:00:00 json sql-update mysql java Hibernate

我有一个非常简单的 mysql 记录,如下所示:

I have a pretty simple mysql record like this:

+------+-------+-----------+
| id   |  name | password  |
+------+-------+-----------+
| 1    | John  | d0c91f13f |
+------+-------+-----------+
 ...      ...     ...

这是它的休眠实体;没什么花哨的

And here is its hibernate entity; nothing fancy

@Entity
@Table(name = "user", schema = "", catalog = "trade")
public class UserEntity{
     private long id;
     private String name;
     private String password;

     @Id
     @Column(name = "id")
     public long getId(){
          return id;
     }
     public void setId(long id){
          this.id = id;
     }

     @Column(name = "name")
     public String getName(){
          return name;
     }
     public void setName(String name){
          this.name = name;
     }

     @Column(name = "password")
     public String getPasswrod(){
          return password;
     }
     public void setPassword(String password){
          this.password = password;
     }
}

为了方便,我使用Gson从前端传入的json字符串中解析实体.
记录的json字符串是这样的:

For convenience, I use Gson to parse the entity from json string which front-end passed in.
The json string for the record is like this:

{"id":1, "name":"John", "password":"d0c91f13f"}

然后会从json字符串中解析userEntity:

then userEntity will be parsed from the json String:

UserEntity userEntity = gson.fromJson(userJson, UserEntity.class);

我可以使用 Session.save(userEntity)Session.update(userEntity) 插入或更新用户.

I can insert or update the user with Session.save(userEntity) and Session.update(userEntity).

如果每个字段都包含在 json 字符串中,那么事情似乎按预期进行.但是当某些字段,例如 password 被省略时:

If every field is contained in the json string, then things seemed goes as expected. But when some field, such as password is omitted:

{"id":1, "name":"John Smith"}

这表明我应该进行部分更新并且不修改省略的字段,但出现了问题.因为解析过程会将 password 设置为 Null.并将其更新到数据库中.

which indicated that I should make a partial update and leave the omitted field not modified, things went wrong. Because the parsing procedure will set password to Null. and update it to the database.

那么,在这种情况下,有没有办法部分更新记录?

So, is there a solution to partially update the record in this case?

遍历每个字段并逐个设置字段将是最后一个选项;除此之外还有什么?

Going through every field and setting fields one by one will be the last option; anything other than that?

提前致谢.

推荐答案

1、假设你可以通过以下方式反序列化srcUserEntity:

1,Suppose you can deserialized srcUserEntity by:

UserEntity srcUserEntity = gson.fromJson(userJson, UserEntity.class);

2、可以利用spring的BeanUtil的copy properties方法.

2, You can leverage spring's BeanUtil's copy properties method.

BeanUtils.copyProperties(srcUserEntity, desUserEntity, SpringBeanUtil.getNullPropertyNames(srcUserEntity));

3,在你的 Dao 层,只需先从数据库中获取模型,然后更新需要更新的属性,最后更新.参考代码如下:

3, In your Dao layer, just fetch the model from Database first, then update the properties needs to be updated only, lastly update. Refer to codes as below:

Session currentSession =  sessionFactory.getCurrentSession();
UserEntity modelInDB = (UserEntity)currentSession.get(UserEntity.class, user.getId());
//Set properties that needs to update in DB, ignore others are null.
BeanUtils.copyProperties(productStatusModelForPatch, modelInDB, SpringBeanUtil.getNullPropertyNames(productStatusModelForPatch));
currentSession.update(modelInDB);

4、getNullPropertyNames()方法请参考[如何使用springframework BeanUtils copyProperties忽略空值?(已解决)

4, for getNullPropertyNames() method, please refer to [How to ignore null values using springframework BeanUtils copyProperties? (Solved)

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); 
}


// then use Spring BeanUtils to copy and ignore null
public static void myCopyProperties(Object, src, Object target) {
    BeanUtils.copyProperties(src, target, getNullPropertyNames(src))
}

相关文章