Java hibernate将表单submit中未包含的实体属性更新为null
我正在使用thymeleaf、Spring和Hibernate构建一个MVC应用程序。我这里的问题更多的是关于冬眠而不是春天 这就是我目前所拥有的 用户界面 道: 控制器中的GET方法将用户对象获取到视图。但是在视图中,我只是在表单中显示了用户对象的一些属性Java hibernate将表单submit中未包含的实体属性更新为null,java,spring,hibernate,spring-mvc,Java,Spring,Hibernate,Spring Mvc,我正在使用thymeleaf、Spring和Hibernate构建一个MVC应用程序。我这里的问题更多的是关于冬眠而不是春天 这就是我目前所拥有的 用户界面 道: 控制器中的GET方法将用户对象获取到视图。但是在视图中,我只是在表单中显示了用户对象的一些属性 <input type='hidden' th:field="*{dateOfBirth}" /> 在表单Submit上,调用控制器中的POST方法,该方法调用服务层,然后执行DAO中的merge方法 现在我观察到的是,实体管
<input type='hidden' th:field="*{dateOfBirth}" />
在表单Submit上,调用控制器中的POST方法,该方法调用服务层,然后执行DAO中的merge方法
现在我观察到的是,实体管理器上的这个合并方法正在将表单中不存在的属性更新为null
我认为这是预期的行为,因为对象在从POST方法调用时是分离的。因此,正确的做法是首先从数据库中获取实体对象,然后向该对象设置表单中更改的字段,然后调用merge方法
有人能告诉我上面我说的是否正确吗
如果是的话,那么我的下一个问题是,这不是很乏味,需要付出更多的努力。我的意思是,在某些情况下,我不想在表单中显示整个对象。也不在隐藏字段中。我很惊讶没有办法处理这个问题,每次我都必须遵循我刚才描述的方法
有更好的方法吗?我不应该改用JDBC模板吗?我知道我会在那里编写锅炉板代码,但我在这里编写getter和setter,以及每次往返到UI时的getter和setter。您可以将以下代码放入util类中,并在希望基于另一个引用对象填充对象时调用它:
public static <T> void fillNotNullFields(T reference, T source) {
try {
Arrays.asList(Introspector.getBeanInfo(reference.getClass(), Object.class)
.getPropertyDescriptors())
.stream()
.filter(pd -> Objects.nonNull(pd.getReadMethod()))
.forEach(pd -> {
try {
Object value = pd.getReadMethod().invoke(source);
if (value != null)
pd.getWriteMethod().invoke(reference, value);
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
我找到了这个答案的支持。希望有帮助。您需要将不必要的bean属性存储在隐藏字段中,以便在表单发布到控制器时重新映射它们。例如,如果您不想在页面上显示出生日期(假设出生日期已经是用户的属性),只需在表单中添加以下标记即可
<input type='hidden' th:field="*{dateOfBirth}" />
考虑使用
org.hibernate.annotations.entity
注释实体
@Entity
@Table(name = "user")
@org.hibernate.annotations.Entity(
dynamicInsert = true, dynamicUpdate=true
)
public class User implements java.io.Serializable {
// your properties
}
如果您使用的是Hibernate的4.x版本,您可能希望改用@DynamicUpdate
,因为@org.Hibernate.annotations.Entity
的用法最近已被弃用
参考资料:
Hibernate对表单一无所知。我看到的典型模式是从db加载实体,将表单中的字段映射到实体,然后持久化实体。我相信有一些spring管道可以帮助解决这个问题,但我记不起谷歌应该找到它的具体细节。是的,但这不是重点,重点是,如果这是hibernate的预期行为,我想知道其他人是如何处理的?如果这不是预期的行为,那么在这种情况下会发生什么?@user641887在这种情况下,我实际上不知道。我只有在使用DTO设计模式的restful web服务中使用hibernate的经验,这个问题与rest方法无关。实际上,在rest中直接从视图层持久化对象并不是一个好的做法。我不想精确地这样做,对于一个用户,我有多个属性,比表单中的属性多得多。。那完全是多余的。。你不这么认为吗?这是大多数框架(比如Grails)中非常常用的策略。如果您确实想避免放置多个隐藏字段,您可能希望查看动态插入。但我的是对现有记录的更新操作。。非插入注释支持插入和更新。基于此,我将在下面添加一个新答案。这是相关的,让我试试,如果我发现有任何问题,我会告诉你。。看起来这样行得通。
public UserBO updateUser(String userId, UserBO user ) {
UserBO reference = findOne(Integer.parseInt(userId));
fillNotNullFields(reference, user);
return updateUser(reference);
}
<input type='hidden' th:field="*{dateOfBirth}" />
@Entity
@Table(name = "user")
@org.hibernate.annotations.Entity(
dynamicInsert = true, dynamicUpdate=true
)
public class User implements java.io.Serializable {
// your properties
}