@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注解相关数据库表: 实体类中字段需要 ...
随机推荐
- JS 的 new 是个啥?
JS 的 new 是个啥? 本文写于 2019 年 11 月 25 日 new关键字在很多语言里面,总是用于把类实例化,可是 JS 之前就没有"类"这个概念呀. 那 JS 的new ...
- 并查集——以nuist OJ P1648炼丹术为例
并查集 定义:并查集是一种树形的数据结构,用于处理一些不相交集合的合并及查询问题 主要构成: 并查集主要由一个整型数组pre[]和两个函数find().join()构成. 数组pre[]记录了每个点的 ...
- 590. N-ary Tree Postorder Traversal - LeetCode
Question 590. N-ary Tree Postorder Traversal Solution 题目大意:后序遍历一个树 思路: 1)递归 2)迭代 Java实现(递归): public ...
- 成本节省 50%,10 人团队使用函数计算开发 wolai 在线文档应用
作者: 马锐拉 我们的日常工作场景几乎离不开"云文档".目前,人们对于文档的需求再不仅仅是简单的记录,而扩展到办公协同.信息组织.知识分享等.在国内众多在线文档中,wolai 因为 ...
- 分享一个 SpringCloud Feign 中所埋藏的坑
背景 前段时间同事碰到一个问题,需要在 SpringCloud 的 Feign 调用中使用自定义的 URL:通常情况下是没有这个需求的:毕竟都用了 SpringCloud 的了,那服务之间的调用都是走 ...
- MongoDB 分片规则
每日一句 生命本身毫无意义,只有死亡才能让你邃晓人性的真谛! 每日一句 Ideal is the beacon. Without ideal, there is no secure direction ...
- application.properties文件中暗藏玄机
上次分享了如何一步一步搭建一个springboot的项目,详细参见<5分钟快速搭建一个springboot的项目>,最终的结果是在"8080"端口搭建起了服务,并成功访 ...
- 一张图进阶 RocketMQ - NameServer
前言 「三此君看了好几本书,看了很多遍源码整理的 一张图进阶 RocketMQ 图片链接,关于 RocketMQ 你只需要记住这张图!觉得不错的话,记得点赞关注哦.」 一张图进阶 RocketMQ 图 ...
- C语言学习之我见-strcpy()字符串复制函数
strcpy()函数,用于两个字符串值的复制. (1)函数原型 char * strcpy(char * _Dest,const char * _Source); (2)头文件 string.h (3 ...
- 理论+案例,带你掌握Angular依赖注入模式的应用
摘要:介绍了Angular中依赖注入是如何查找依赖,如何配置提供商,如何用限定和过滤作用的装饰器拿到想要的实例,进一步通过N个案例分析如何结合依赖注入的知识点来解决开发编程中会遇到的问题. 本文分享自 ...