0

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

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"}

then userEntity will be parsed from the json String:

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

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

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"}

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?

Thanks in advance.

Strawberry
  • 33,750
  • 13
  • 40
  • 57
armnotstrong
  • 8,605
  • 16
  • 65
  • 130

2 Answers2

0

If you know a particular entry exists, then fetching the entry before updating would fill the object with the existing values and you'd only change the values your Json provided. This avoids null updates like you describe.

If, however, the entry is new, then whatever is missing in the Json will be passed as null to the database.

Waldo Terry
  • 118
  • 1
  • 7
  • Can you explain more specifically? what do u mean by "fetch"? such as `UserEntity user = gson.fromJson(json, UserEntity.class); session.get(UserEntity, userEntity.getId()); session.update(userEntity)` ? I will try that. – armnotstrong Dec 20 '14 at 08:39
  • I mean that you should retrieve UserEntity stored in the database first, and make any changes to this retrieved object. After you're done, update it. Since you got the object from the database, any property you did not change will have the values stored in the database and should not change. – Waldo Terry Dec 20 '14 at 08:43
  • I know that will work, but In order to make that work I should deserialize the json string manually and set properties according to which field it contains using reflect(may be?), some job `gson.fromJson()` has already done. – armnotstrong Dec 20 '14 at 08:54
  • using reflection on the method reconstituting the object from Json would work, yes. You could also place a method in UserEntity annotated with `@PreUpdate` like so: `@PreUpdate public void validateJsonInput(UserEntity entity)`. The parameter is the object that is about to be updated; you can take this object's id and retrieve the original from the database within this method and perform all relevant checks here without bothering with reflection in the class that is working with Json. – Waldo Terry Dec 20 '14 at 17:03
0

1,Suppose you can deserialized srcUserEntity by:

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

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

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

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, 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))
}
Community
  • 1
  • 1
Zhe
  • 29
  • 3