@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注解相关数据库表: 实体类中字段需要 ...
随机推荐
- 一条Sql的执行过程
一条sql内部是如何执行的: 学习MySQL实战45专栏 sql中的内部执行图: 可以分为两部分:server和存储引擎 server层包含: 连接器.分析器.优化器.执行器,涵盖了MySQL大多数核 ...
- 2020级cpp机考模拟题A卷-#题解1
为了各位朋友的身心健康(不是),我们按照题目难度顺序来写题解. 第一次写题解,希望多点包容和鼓励(恬不知耻 1:谁先输出-4 题意: 输入3个整数,按从大到小的顺序输出,每两个数字间加一个空格. 题解 ...
- .NET性能优化-推荐使用Collections.Pooled
简介 性能优化就是如何在保证处理相同数量的请求情况下占用更少的资源,而这个资源一般就是CPU或者内存,当然还有操作系统IO句柄.网络流量.磁盘占用等等.但是绝大多数时候,我们就是在降低CPU和内存的占 ...
- MUI+html5的plus.webview页面传值在电脑浏览器上不可见
使用plus.webview.currentWebview() 获得当前窗口的webview对象后,再使用document.write()输出显示webview的某个属性值,而plus.webview ...
- ASP.NET MVC 处理管线模型
MVC管道整体处理模型 1.在ASP.NET MVC处理管线中的第一站就是路由模块.当请求到达路由模块后,MVC框架就会根据Route Table中配置的路由模板来匹配当前请求以获得对应的contro ...
- 第06组Alpha冲刺总结
目录 1. 基本情况 2. 思考与总结 2.1. 设想和目标 2. 计划 3. 资源 4. 变更管理 5. 设计/实现 6. 测试/发布 7. 团队的角色,管理,合作 8. 总结 3. 敏捷开发 1. ...
- Codeforces Round #773 (Div. 2)
这一场打的非常一般,不过把D想出来了(当然只剩10min没有写出来). A.Hard Way 题意:(很怪的题,我读题读半天)给你一个三角形(端点都在整数点上),问从x轴往上划线(不一定垂直)画不到的 ...
- 牛客多校赛2K Keyboard Free
Description 给定 \(3\) 个同心圆,半径分别为 \(r1,r2,r3\) ,三个点分别随机分布在三个圆上,求这个三角形期望下的面积. Solution 首先可以固定 \(A\) 点,枚 ...
- nazo.io 通关记录
游戏网址 说在前面 答案错误页面 nazo.io/wrong 攻略 第0关 谜.io 纯粹是欢迎你来游戏. 所以他给你的start就是答案. 第1关 欢迎 它用灰体字写了key: welcome 直接 ...
- React中使用react-player 播放视频或直播
业务中需要播放视频,寻来寻去,找到了react-player 初次点击,甚是眼熟,思来想去,竟是钉钉同款 如果使用react框架 先安装 npm install --save video-react ...