如何让jpa 持久化时不校验指定字段

简介: 源文:https://www.toocruel.net/jpa-validate/ 怎么让jpa 持久化时不校验指定字段本文提供全流程,中文翻译。

源文:https://www.toocruel.net/jpa-validate/

怎么让jpa 持久化时不校验指定字段


本文提供全流程,中文翻译。

Chinar 坚持将简单的生活方式,带给世人!

(拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)



Chinar —— 心分享、心创新!

助力快速完成jpa 持久化时不校验指定字段/文字

为新手节省宝贵的时间,避免采坑!




全文高清图片,点击即可放大观看 (很多人竟然不知道)


1

Problem —— 问题/需求


spring data jpa ,使用了 validate 校验

校验直接加在了要持久化实体类上,为了方便简洁并没有使用 DTO 做验证

但是有的校验仅在 Controller 层需要校验,持久化时不需校验

因为我把他声明为 @Transient 的了,如下 User 类:

举个栗子黑白88

/// <summary>
/// 用户类
/// </summary>
public class User {
    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空")
    private String username;
    /**
     * 密码
     */
    private String password;

    /**
     * 角色id
     */
    @NotEmpty(message = "角色id不能为空")
    @Transient
    private Long[] roleIds;

    /**
     * 用户的所有角色
     */
    @ManyToMany(cascade = CascadeType.DETACH)
    @JoinTable(name = "user_role_relation",joinColumns =      @JoinColumn(name = "userId"),inverseJoinColumns = @JoinColumn(name = "roleId"))
    @JsonIgnoreProperties("users")
    private Set<Role> roles = new HashSet<>();

     //...省略 gets and sets
}


其中, roleIds 属性是 Transient 的,表明了不做持久化

我用它只是在 Controller 接收 form 表单提交时要校验

校验通过存入 roles 属性,并不需要在持久化时校验

(但是 jpa 规范或者说 Hibernate 在持久化时会校验所有属性包括 Transient 的)


2

Wrong again —— 错误重现


执行 userRepository.save(new User()), 报错:
举个栗子黑白88

javax.validation.ConstraintViolationException: Validation failed for classes [net.toocruel.iqismart.entity.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
    ConstraintViolationImpl{interpolatedMessage='角色id不能为空', propertyPath=roleIds, rootBeanClass=class net.toocruel.iqismart.entity.User, messageTemplate='角色id不能为空'}
]
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:138) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:78) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.action.internal.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:197) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:75) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:619) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:273) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:254) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:299) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:317) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:272) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:109) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:67) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
    at sun.reflect.GeneratedMethodAccessor190.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298) ~[spring-orm-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at com.sun.proxy.$Proxy145.persist(Unknown Source) ~[na:na]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508) ~[spring-data-jpa-1.11.6.RELEASE.jar:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:504) ~[spring-data-commons-1.13.6.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:489) ~[spring-data-commons-1.13.6.RELEASE.jar:na]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461) ~[spring-data-commons-1.13.6.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.10.RELEASE.jar:4.3.10.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) ~[spring-data-commons-1.13.6.RELEASE.jar:na]
...
...

3

SoluTion —— 解决方案


从上面关键错误信息:

Validation failed for classes [net.toocruel.iqismart.entity.User] during persist time for groups [javax.validation.groups.Default, ]

可以看到,虽然给roleIds加了@Transient注解,JPA仍旧进行了校验,还发现有个groups:

[javax.validation.groups.Default, ]


原来,jpa validate 是可以分组校验,默认的有个组default,持久化时要校验这个组 , 不指定时就是默认的

比如,roleIds的@NotEmpty(message = "角色id不能为空")未指定groups,那它就是默认组的,持久化时会被校验的。

由此,有了一个想法,把roleIds的校验组不使用默认,而是设置为另一个组,这样似乎可行。

于是,修改User roleIds的校验注解:
举个栗子黑白88

@NotEmpty(message = "角色id不能为空",groups = ControllerGroup.class)
@Transient
private Long[] roleIds;

增加了groups = ControllerGroup.class,其中 ControllerGroup 是随便新建一个类或接口都可以。

至此:如期所料,完美解决!


支持

May Be —— 搞开发,总有一天要做的事!


拥有自己的服务器,无需再找攻略!

Chinar 提供一站式教程,闭眼式创建!

为新手节省宝贵时间,避免采坑!


先点击领取 —— 阿里全产品优惠券 (享受最低优惠)


1 —— 云服务器超全购买流程 (新手必备!)

2 —— 阿里ECS云服务器自定义配置 - 购买教程(新手必备!)

3—— Windows 服务器配置、运行、建站一条龙 !

4 —— Linux 服务器配置、运行、建站一条龙 !



70

技术交流群:806091680 ! Chinar 欢迎你的加入


END

本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址
>

相关文章
|
SQL 数据库
传递给数据库 'model' 中的日志扫描操作的日志扫描号无效
原文:传递给数据库 'model' 中的日志扫描操作的日志扫描号无效 状况描述:在服务器的管理中重新启动MSSQLSERVER启动后马上又停止   通过"事件查看器" 发现 错误: 9003,严重度: 20,状态: 1 LSN(5:324:1)无效。
3067 0
|
7月前
|
前端开发 Java 数据库
Spring Entity数据校验,分组校验,返回校验结果给前端
Spring Entity数据校验,分组校验,返回校验结果给前端
64 0
|
3月前
|
数据格式 Python
添加 常用校验方法,校验常见数据格式
添加 常用校验方法,校验常见数据格式
23 0
|
4月前
|
数据安全/隐私保护
离线表数据敏感字段自动id化处理
离线表数据敏感字段自动id化处理
47 0
|
11月前
分组校验和自定义校验
分组校验和自定义校验
60 0
GoFrame数据校验之校验对象 | 校验结构体
这篇文章将会为大家介绍GoFrame数据校验中校验对象的知识点,包括:Validator对象常用方法的介绍、单数据校验、校验Map、校验结构体的示例
132 0
GoFrame数据校验之校验对象 | 校验结构体
|
前端开发
GoFrame数据校验之校验结果 | Error接口对象
这篇总结分享:GoFrame数据校验的另外一个知识点:校验结果相关的总结分享。
133 0
|
运维 前端开发 JavaScript
如何优雅的校验参数
数据的校验是交互式网站一个不可或缺的功能,前端的js校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已。可以使用本文将要介绍的validation来对数据进行校验。
341 0
如何优雅的校验参数