当前位置: 首页 > 知识库问答 >
问题:

如何只更新Hibernate中JSON定义的属性

龚彬
2023-03-14

我正在创建一个SpringBoot/Angular 8应用程序,并在尝试更新解耦的前端/后端对象时遇到一些问题。当我发送包含角模型的json post请求时,@JsonIgnore'd或其他缺失的值将被更新为null,而不是被忽略。

这个堆栈溢出问题与此密切相关,推荐的解决方案确实有效,但它打断/绕过了一系列Jackson/Hibernate注释(例如@heritance(strategy=heritanceType.JOINED)@Transient),所以,如果可能的话,我想寻找其他的解决方案:当使用json解析实体时,hibernate会部分更新

@Entity
@Table(name = "users")
@DynamicUpdate
public class User implements Serializable{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String a;

    @Column
    private String b;

    @Column (nullable = false)
    @JsonIgnore
    private String c;

   // standard getters and setters
}
@RequestMapping(value = "/api/user", method = RequestMethod.POST)
public @ResponseBody ResponseEntity<User> saveOrUpdate(@RequestBody User user, BindingResult result, HttpServletRequest request) {
    if(user.getId()!=null){
        user=ws.update(user);
    }else{
        user=us.create(user);
    }
    return new ResponseEntity<>(user,HttpStatus.OK);
}

saveUser(user:User): Observable<User>{
    const body = JSON.stringify(user);
    return this.http.post<User>('/api/user', body).pipe(map( response => response));
}
{ 
  id:1,
  a:"some value a"
  b:"some value b"
  c:"some value c"
}
{ 
  id:1,
  a:"some value a2"
  b:"some value b2"
}

更新用户集a=?,b=?其中id=

更新用户集a=?,b=?,c=?其中id= C是一个空值。


共有3个答案

裴育
2023-03-14

我最终修改了现有的解决方案,并使用反射为有问题的注释添加了排除项。

此解决方案基本上只是从会话中提取现有模型,并跨会话复制所有非null属性。然后,上面提到的@DynamicUpdate属性确保只更新修改后的属性。

protected String[] getNullPropertyNames (T source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set<String> emptyNames = new HashSet<String>();
        boolean skipProperty;
        for(java.beans.PropertyDescriptor pd : pds) {
            skipProperty=false;
            if(pd.getReadMethod()!=null) {
                for (Annotation a : pd.getReadMethod().getAnnotations()) {
                    if (a.toString().equals("@javax.persistence.Transient()")) {/*Skip transient annotated properties*/
                        skipProperty = true;
                    }
                }
            }else{
                skipProperty=true;
            }
            if(!skipProperty){
                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 void copyUpdatedProperties(T newEntity, T existingEntity) {
        BeanUtils.copyProperties(newEntity, existingEntity, getNullPropertyNames(newEntity));
    }

这解决了我所有的直接问题,但是我怀疑注释@In的继承(策略=继承类型。JOINED)可能会在以后导致问题。

司马高韵
2023-03-14

我没有尝试过这一点,但是设置dynamicUpdate=true应该可以完成这项工作。(如果您不知道将更改哪些属性,这可能是唯一的干净选项,因为前端只发送更改的属性)。请遵循本教程并让我知道它是否正常工作:Hibernate–动态更新属性示例

陈茂
2023-03-14

不要对从角发送的对象使用更新方法,因为它替换了数据库中的整个原始对象。在更新的情况下,我建议你从数据库中检索存在的对象(例如,使用Spring数据存储库findOne方法),然后只复制修改过的字段,忽略空值。您可以使用Apache共享库中的BeanUtils复制属性方法。原始方法在复制时不会忽略空值,因此您必须稍微重写它:

public class NullAwareBeanUtilsBean extends BeanUtilsBean {
    @Override
    public void copyProperty(Object dest, String name, Object value) throws IllegalAccessException, InvocationTargetException {
        if (value == null)
            return;
        super.copyProperty(dest, name, value);
    }
}

这个测试再现了你想要做的事情:

要更新的类:

public class A {

    private String foo;

    private String bar;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }
}

测试等级:

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.lang3.builder.ToStringBuilder;

import com.zpavel.utils.NullAwareBeanUtilsBean;

public class MyTest {

    public static void main(String[] args) throws IllegalAccessException, InvocationTargetException {
        A a1 = new A();
        a1.setFoo("foo");
        A a2 = new A();
        a2.setBar("bar");
        BeanUtilsBean notNull = new NullAwareBeanUtilsBean();
        notNull.copyProperties(a2, a1);
        System.out.println(ToStringBuilder.reflectionToString(a2));
    }
}
 类似资料:
  • 我正在使用Spring Data MongoDB和Spring Data Rest创建一个Rest API,它允许对我的MongoDB数据库进行GET、POST、PUT和DELETE操作,除了更新操作(PUT)之外,其他操作都很好。只有当我在请求体中发送完整的对象时,它才起作用,否则变量没有在rquest中发送它,则为NULL。有人能指导我解决这个问题吗。

  • 下面是我的JSON: 我想用下面的规则更新上述JSON字符串的两个属性: 标志:我想盲目地将此属性更新为。 infoFlag:如果< code>info的< code>name属性为< code>null,那么我希望将< code>infoFlag更新为< code>true否则为< code>false,如果它为< code>not null。 因此,在用这些规则更新JSON之后,我希望将JSO

  • Hibernate的property元素具有update、insert属性,根据文档,它声明-http://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/mapping.html#mapping-声明属性 update,insert(可选-默认为true):指定映射列应包含在SQL update和/或insert语句中。将两者都设置为f

  • 我已经扩展了TreeCell和TreeItem类。MyTreeItem包含一个自定义属性,我在MyTreeCell中使用它来渲染图形/字体等。问题是当我设置MyTreeCell.custom属性我不知道如何使TreeView/单元格重绘。 例如: 任何关于解决方案或(缺乏)设计方法的意见都受到赞赏。

  • 在几个表中有几列数据库列定义从实体中的声明更改。喜欢 和 mycolumn' bigint(20) not null默认值为0 在 MySQL 中。 为什么hbm2ddl不更新这样的东西?有可能强制这样的更新吗?我想说hbm2ddl删除列的默认值并更改类型的长度。

  • 是否可以通过KeyClope REST API更新自定义属性的值?例如,要使用哪个endpoint,以及如何为此处创建的属性构造请求主体。 谢谢