@Convert 注解在jpa中进行查询的注意事项
如果要实现实体类中属性的类型和数据库表中字段的类型相互转化,则需要使用 @Convert 注解
package javax.persistence; import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; @Repeatable(Converts.class)
@Target({METHOD, FIELD, TYPE})
@Retention(RUNTIME)
public @interface Convert { /**
* 指定要使用的转换器
*/
Class converter() default void.class; /**
* 当注解 Convert 应用在基本类型的属性或基本类型的元素集合上,不能指定attributeName元素。
*/
String attributeName() default ""; /**
* 用于禁用自动应用或继承的转换器。如果 disableConversion 为真,则不应指定converter元素
*/
boolean disableConversion() default false;
}
由 Convert 源码可知:使用 @Convert 注解需要一个转换器,
自定义转换器需要实现 AttributeConverter 接口
1、AttributeConverter 接口
package javax.persistence; /**
*
* 把实体类中属性的类型与数据库表中字段的类型相互转换.
*
* @param <X> 实体类中的属性类型
* @param <Y> 数据库表中的字段类型
*/
public interface AttributeConverter<X,Y> { /**
* 实体类中属性的类型转换为数据库表中字段的类型
*
* @param 实体类中属性的类型
* @return 数据库表中字段的类型
*
*/
public Y convertToDatabaseColumn (X attribute); /**
* 数据库表中字段的类型转换为实体类中属性的类型
*
* @param 数据库表中字段的类型
* @return 实体类中属性的类型
*
*/
public X convertToEntityAttribute (Y dbData);
}
2、自定义的实现类
package com.chayiges; import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.time.YearMonth; /**
* 使用 JPA 将 YearMonth 持久化为整数
*
* @author chayiges
*/
// 标识该类是转换器
@Converter
public class YearMonthIntegerAttributeConverter
implements AttributeConverter<YearMonth, Integer> { /**
* 实体类 -> 数据库
* 向数据库中保存时调用
*/
@Override
public Integer convertToDatabaseColumn(YearMonth attribute) {
if (attribute != null) {
return (attribute.getYear() * 100) + attribute.getMonth().getValue();
}
return null;
} /**
* 数据库 -> 实体类
* 向数据库中查询时调用
*/
@Override
public YearMonth convertToEntityAttribute(Integer dbData) {
if (dbData != null) {
int year = dbData / 100;
int month = dbData % 100;
return YearMonth.of(year, month);
}
return null;
}
}
1.2、创建数据库对应的实体类
package com.chayiges; import jp.co.isid.cas3.commons.api.jpa.AbstractAggregateRoot;
import jp.co.isid.cas3.onecas.core.YearMonthIntegerAttributeConverter;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor; import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.Serializable;
import java.time.YearMonth;
import java.util.UUID; /**
* 学生表对应的实体类
*
* @author chayiges
*/
@Entity
@Getter
@Table
@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true)
@AllArgsConstructor
public class Student extends AbstractAggregateRoot<Student, UUID> implements Serializable { /** ID */
@EmbeddedId
private UUID id; /** 姓名 */
@Column(name = "user_name", length = 100, nullable = false)
private String userName; /** 年月 */
@Convert(converter = YearMonthIntegerAttributeConverter.class)
@Column(name = "year_month")
private YearMonth yearMonth; }
1.3、创建 jpa 查询
package com.chayiges; import org.springframework.data.jpa.repository.JpaRepository; import java.time.YearMonth;
import java.util.UUID; /**
* 学生表的jap查询
*
* @author chayiges
*/
public interface Students extends JpaRepository<Student, UUID> { /**
* 根据年月查询学生表
* @param yearMonth 年月
* @return 学生表
*/
List<Student> findByYearMonth(YearMonth yearMonth); }
1.4、测试
package jp.chayiges; import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test; import java.time.YearMonth;
import java.util.UUID;
import java.util.List; /**
* jap查询测试
*
* @author chayiges
*/
@RequiredArgsConstructor
public class StudentJPAUnitTests { /** 实体类到数据库表的转换器 */
final YearMonthIntegerAttributeConverterauto yearMonthIntegerAttributeConverterauto; /** 学生表 jpa */
final Students students; /**
* テスト
*/
@Test
void findByYearMonthTest() { YearMonth yearMonth = YearMonth.of(2022, 7);
// 创建学生对象
Student stu = new Student("a57988c3-1711-4288-9623-9e7c177ff078",
"孙汐", yearMonth);
// 调用 jpa 方法进行保存,保存的时候会进入自定义的Convert实现类中进行实体类属性值到数据
// 库中对应字段值的转换
this.students.save(stu); // 调用 jpa 方法查询
List<Student> studentList = this.students.findByYearMonth(yearMonth); }
}
1.5、创建了错误的 jpa 方法
package com.chayiges; import org.springframework.data.jpa.repository.JpaRepository; import java.time.YearMonth;
import java.util.UUID; /**
* 学生表的jap查询
*
* @author chayiges
*/
public interface Students extends JpaRepository<Student, UUID> { /**
* 根据年月查询学生表
* @param yearMonth 年月
* @return 学生表
*/
List<Student> findByYearMonth(Integer integer); }
1.6、错误的 jpa 方法的测试
package jp.chayiges; import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test; import java.time.YearMonth;
import java.util.UUID;
import java.util.List; /**
* jap查询测试
*
* @author chayiges
*/
@RequiredArgsConstructor
public class StudentJPAUnitTests { /** 实体类到数据库表的转换器 */
final YearMonthIntegerAttributeConverterauto yearMonthIntegerAttributeConverterauto; /** 学生表jpa */
final Students students; /**
* テスト
*/
@Test
void findByYearMonthTest() { YearMonth yearMonth = YearMonth.of(2022, 7);
// 创建学生对象
Student stu = new Student("a57988c3-1711-4288-9623-9e7c177ff078",
"孙汐", yearMonth);
// 调用 jpa 方法进行保存,保存的时候会进入自定义的Convert实现类中进行实体类属性值到数据
// 库中对应字段值的转换
this.students.save(stu); // 调用 jpa 方法查询,会抛出 InvalidDataAccessApiUsageException 异常
List<Student> studentList = this.students.findByYearMonth(this
.yearMonthIntegerAttributeConverterauto
.convertToDatabaseColumn(yearmonth));
}
}
注意:此处查询年月的时候用的是实体类中 YearMonth 类型,并不是转换到数据库中的 Integer 类型
至于数据保存到数据库中确实是 Integer 类型,但是查询的时候依然要使用实体类中属性的类型这个问题,本人也不知其中缘由,有懂的大佬麻烦指出
@Convert 注解在jpa中进行查询的注意事项的更多相关文章
- JPA 中注解的作用
JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. JPA由EJB 3.0软件专家 ...
- 使用JPA中@Query 注解实现update 操作
spring使用jpa进行update操作主要有两种方式: 1.调用保存实体的方法 1)保存一个实体:repository.save(T entity) 2)保存多个实体:repository.sav ...
- JPA中EntityListeners注解的使用
使用场景 EntityListeners在jpa中使用,如果你是mybatis是不可以用的 它的意义 对实体属性变化的跟踪,它提供了保存前,保存后,更新前,更新后,删除前,删除后等状态,就像是拦截器一 ...
- Spring data JPA中使用Specifications动态构建查询
有时我们在查询某个实体的时候,给定的条件是不固定的,这是我们就需要动态 构建相应的查询语句,在JPA2.0中我们可以通过Criteria接口查询,JPA criteria查询.相比JPQL,其优势是类 ...
- Spring Data JPA中的动态查询 时间日期
功能:Spring Data JPA中的动态查询 实现日期查询 页面对应的dto类private String modifiedDate; //实体类 @LastModifiedDate protec ...
- spring boot JPA中实体类常用注解
spring boot jpa中的注解很多,参数也比较多.没必要全部记住,但是经常查看官方文档也比较麻烦,记录一下一些常用的注解.通过一些具体的例子来帮助记忆. @Entity @Table(name ...
- 【hql】spring data jpa中 @Query使用hql查询 问题
spring data jpa中 @Query使用hql查询 问题 使用hql查询, 1.from后面跟的是实体类 不是数据表名 2.字段应该用实体类中的字段 而不是数据表中的属性 实体如下 hql使 ...
- jpa中使用Query判断条件查询
jpa中使用Query判断条件查询 @Query(value = " select m.* from mining_area as m " + " where 1 = 1 ...
- JPA中建立数据库表和实体间映射小结
在JPA中,映射数据库表和实体的时候,需要注意一些细节如下, 实体类要用@Entity的注解: 要用 @Id 来注解一个主键: 如果跟数据库相关联,要用@Table注解相关数据库表: 实体类中字段需要 ...
随机推荐
- springcloud + nacos实现共用基础服务(灰度版本)
背景: 当我们使用微服务时,若想在本地联调就需要启动多个服务,为了避免本地启动过多服务,现将注册中心等基础服务共用.当我们在服务A开发时,都是注册到同一个nacos,这样本地和开发环境的服务A就会同时 ...
- SpringBoot实现基于token的登录验证
一.SpringBoot实现基于token的登录验证 基于token的登录验证实现原理:客户端通过用户名和密码调用登录接口,当验证数据库中存在该用户后,将用户的信息按照token的生成规则,生成一个字 ...
- Redis 全局通用命令整理
转载请注明出处: 1.查看所有键 keys * 该命令会存在线程阻塞问题,keys 命令也可以通过正则匹配获取存在的缓存数据 2.查看键总数 dbsize dbsize命令会返回当前数据库中键的总数. ...
- vue 的个人学习小笔记
一.vite2.0+vue3.0+ts 创建.配置 个人公众号文章地址 个人github仓库地址 1.Vite 创建 vue3 项目: 1.1.npm 常用命令 1.npm 查看版本号 npm vie ...
- Pandas复杂查询、数据类型转换、数据排序
Pandas高级操作 1.复杂查询 (1)逻辑运算 以DataFrame其中一列进行逻辑计算,会产生一个对应的bool值组成的Series 于是我们可以利用返回的bool列表进行一系列的数据查询 (2 ...
- java和.net 双语言开发框架,开源的PaaS平台
当下,我国国内的PaaS平台正在蓬勃发展,各式各样的PaaS平台层出不穷,但万变不离其宗,一个优秀的PaaS平台总有自己独树一帜或与众不同的地方.那么,首先我们要了解下什么是PaaS平台?PaaS是( ...
- uniapp项目vue2升级vue3简单记录
看到好多开源项目都升级了vue3,看文章说vue3性能升级很多,而且组合式api很香,遂把最近开发的自助洗车app升级下,在此记录下出现的问题. uniapp升级vue3官方指南 我是先去vue官网看 ...
- python基础学习7
python基础学习7 内容概要 字符串的内置方法 字符串的内置方法(补充) 列表的内置方法 可变类型与不可变类型 队列与堆栈 内容详情 字符串的内置方法 # 1.strip 移除字符串首尾的指定字符 ...
- 验证cuda和cudnn是否安装成功(转载)
本人cuda安装目录: 当然cuda安装目录也可默认:此处为方便安装不同cuda版本,所以单独建了文件夹. 转载自:https://zhuanlan.zhihu.com/p/139668028 安装完 ...
- RMQ——ST表
ST表 ST表是一种解决RMQ问题的强有力工具, 可以做到O(nlogn)预处理,O(1)查询. st[i][j] 表示区间 [i, i + 2 ^ j - 1] 的最大值. 初值 st[i][0] ...