在JPA 2.1中使用@Convert正确完成映射枚举

如果您曾经在JPA中使用过Java枚举,那么您肯定会意识到它们的局限性和陷阱。 使用enum作为@Entity的属性通常是一个很好的选择,但是2.1之前的JPA不能很好地处理它们。 它给了您2 + 1个选择:

托肖夫达林

托肖夫达林

  1. @Enumerated(EnumType.ORDINAL) (默认值)将使用Enum.ordinal()映射enum值。 基本上,第一个枚举值将在数据库列中映射为0 ,第二个映射为1 ,依此类推。这非常紧凑,并且在要修改枚举时非常有用。 在中间删除或增加值或重新排列它们将完全破坏现有记录。 哎哟! 更糟糕的是,单元测试和集成测试通常在干净的数据库上运行,因此它们不会发现旧数据之间的差异。
  2. @Enumerated(EnumType.STRING)更安全,因为它存储enum字符串表示形式。 现在,您可以安全地添加新值并移动它们。 但是,重命名Java代码中的enum仍会破坏DB中的现有记录。 更重要的是,这种表示非常冗长,不必要地消耗了数据库资源。
  3. 您还可以使用原始表示形式(例如single charint ),并在@PostLoad / @PrePersist / @PreUpdate事件中手动来回映射它。 从数据库角度来看,最灵活,最安全,但是很丑陋。

幸运的是,几天前发布的Java Persistence API 2.1 ( JSR-388 )提供了可插拔数据转换器的标准化机制。 这样的API以专有形式存在很久了,它并不是真正的火箭科学,但是将其作为JPA的一部分是一个很大的改进。 据我所知, Eclipselink是迄今为止唯一可用的JPA 2.1实现,因此我们将使用它进行一些实验。

我们将从作为“ 穷人的CRUD:jqGrid,REST,AJAX和Spring MVC一屋子 ”的一部分开发的示例Spring应用程序开始。 该版本没有持久性,因此我们将在由Eclipselink支持的Spring Data JPA之上添加薄DAO层。 到目前为止,只有实体是Book

@Entity
public class Book {@Id@GeneratedValue(strategy = IDENTITY)private Integer id;//...private Cover cover;//...
}

其中Coverenum

public enum Cover {PAPERBACK, HARDCOVER, DUST_JACKET}

ORDINALSTRING都不是一个很好的选择。 前者是因为以任何方式重新排列前三个值都会破坏现有记录的加载。 后者太冗长。 这是JPA中的自定义转换器起作用的地方:

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;@Converter
public class CoverConverter implements AttributeConverter<Cover, String> {@Overridepublic String convertToDatabaseColumn(Cover attribute) {switch (attribute) {case DUST_JACKET:return "D";case HARDCOVER:return "H";case PAPERBACK:return "P";default:throw new IllegalArgumentException("Unknown" + attribute);}}@Overridepublic Cover convertToEntityAttribute(String dbData) {switch (dbData) {case "D":return DUST_JACKET;case "H":return HARDCOVER;case "P":return PAPERBACK;default:throw new IllegalArgumentException("Unknown" + dbData);}}
}

好吧,亲爱的读者,我不会侮辱您,对此进行解释。 将枚举转换为将存储在关系数据库中的任何内容,反之亦然。 从理论上讲,如果使用以下声明,JPA提供程序应自动应用转换器:

@Converter(autoApply = true

它对我不起作用。 此外,在@Entity类中显式声明它们而不是@Enumerated也不起作用:

import javax.persistence.Convert;//...@Convert(converter = CoverConverter.class)
private Cover cover;

导致异常:

Exception Description: The converter class [com.blogspot.nurkiewicz.CoverConverter]
specified on the mapping attribute [cover] from the class [com.blogspot.nurkiewicz.Book] was not found.
Please ensure the converter class name is correct and exists with the persistence unit definition.

错误或功能,我不得不在orm.xml提及转换器:

<?xml version="1.0"?>
<entity-mappings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm" version="2.1"><converter class="com.blogspot.nurkiewicz.CoverConverter"/>
</entity-mappings>

它飞! 我可以自由修改我的Cover枚举(添加,重新排列,重命名),而不会影响现有记录。

我想与您分享的一个技巧与可维护性有关。 每次您有一段从或到enum的代码映射时,请确保已对其进行了正确的测试。 我并不是说要手动测试每个可能的现有值。 为了确保新的enum值在映射代码中得到反映,我进行了更多测试。 提示:如果您添加新的enum值,但是忘记从中添加映射代码则下面的代码将失败(通过抛出IllegalArgumentException ):

for (Cover cover : Cover.values()) {new CoverConverter().convertToDatabaseColumn(cover);
}

JPA 2.1中的自定义转换器比我们所看到的有用得多。 如果将JPA与Scala结合使用,则可以使用@Converter将数据库列直接映射到scala.math.BigDecimalscala.Option或小写类。 在Java中,最终将有一种可移植的方式来映射Joda时间 。 最后但并非最不重要的一点是,如果您喜欢(非常)强类型的域,则可能希望拥有PhoneNumber类(带有isInternational()getCountryCode()和自定义验证逻辑),而不是Stringlong 。 JPA 2.1中的这一小增加肯定会显着提高域对象的质量。

如果您想使用此功能, 可以在GitHub上找到示例Spring Web应用程序。

参考: Java和社区博客中的JCG合作伙伴 Tomasz Nurkiewicz 在JPA 2.1中使用@Convert进行了正确的映射枚举 。

翻译自: https://www.javacodegeeks.com/2013/06/mapping-enums-done-right-with-convert-in-jpa-2-1.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python里orient_OrientDB Python连接操作

OrientDB Python连接操作Python的OrientDB驱动程序使用二进制协议。 PyOrient是git hub项目名称&#xff0c;它用于将OrientDB与Python连接起来并操作数据。 它适用于OrientDB 1.7及更高版本。以下命令用于安装PyOrient。pip install pyorient可以使用名为demo.py的脚本文件执行…

HTML5-画布(canvas)效果之-渐变色

<!DOCTYPE HTML><html><head> <title>渐变色</title></head><body> <canvas id"canvas" width"200" height"100" style"background-color: rgb(222, 222, 222)"> 您的浏…

ssh架构之hibernate(一)简单使用hibernate完成CRUD

1.Hibernate简介 Hibernate是一个开放源代码的对象关系映射(ORM)框架&#xff0c;它对JDBC进行了非常轻量级的对象封装&#xff0c;它将POJO与数据库表建立映射关系&#xff0c;是一个全自动的orm框架&#xff0c;hibernate可以自动生成SQL语句&#xff0c;自动执行&#xff0c…

使用AspectJ审计Spring MVC Webapp。 第1部分

如果您像我一样&#xff0c;那么您将拥有那种编程天&#xff0c;一切似乎都进展顺利。 您编写代码和测试&#xff0c;它就可以正常工作。 然后还有其他日子&#xff0c;非常糟糕的日子&#xff0c;在那儿&#xff0c;您知道所编写的所有内容都尽可能正确&#xff0c;并且代码拒…

GitHub注册和Git安装

一、注册GitHub GitHub官方地址&#xff1a;https://github.com。 在浏览器中打开GitHub网址&#xff0c;通过首页进行注册&#xff0c;如下图所示。 二、安装Git Git官方下载地址&#xff1a;http://git-scm.com/download/。 Git支持多平台&#xff08;Mac OS X/Windows/Linux…

django mysql迁移_关于django 数据库迁移(migrate)应该知道的一些事

命令首先数据库迁移的两大命令&#xff1a;python manage.py makemigrations & python manage.py migrate前者是将model层转为迁移文件migration&#xff0c;后者将新版本的迁移文件执行&#xff0c;更新数据库。这两中命令调用默认为全局&#xff0c;即对所有最新更改的mo…

如何存储和恢复 HTML5 Canvas 状态

当我们在 HTML5 Canvas 上使用其 2D 上下文进行图形绘制的时候&#xff0c;可以通过操作 2D 上下文的属性来绘制不同风格的图形&#xff0c;例如不同字体、填充等等。 通常情况下&#xff0c;在画布上的绘图时&#xff0c;您需要更改在绘制的2D背景下的状态。例如&#xff0c;你…

通过JNI使用C ++尖叫快速进行Lucene搜索

一天结束时&#xff0c;Lucene执行查询时&#xff0c;在初始设置后&#xff0c;真正的热点通常是相当基本的代码&#xff0c;它解码整数docID&#xff0c;术语频率和位置的顺序块&#xff0c;并对其进行匹配&#xff08;例如&#xff0c;对BooleanQuery并集或交集&#xff09;&…

“我们应当怎样做需求分析”——大纲卷

这是一篇关于怎么进行软件需求分析的文章&#xff0c;读完的第一个感觉就是累。真的是特别累&#xff0c;我大概估计了一下&#xff0c;得有40000个字。不过读完之后还是有一点收获的。下面是一个大概的内容。 一.需求调研阶段 初识1.在客户组织的第一场见面会上&#xff0c;保…

动态语言

这是动态语言和静态语言&#xff08;例如Java&#xff09;最大的差别之一。动态语言调用实例方法&#xff0c;不检查类型&#xff0c;只要方法存在&#xff0c;参数正确&#xff0c;就可以调用。 %d:输入输出中的格式控制,以整数的形式输入输出.%f:输入输出中的格式控制,以小数…

innodb和my查询速度_吃透MySQL:MyISAM和InnoDB存储引擎详细介绍

一&#xff0c;MySQL基本架构MySQL基础架构可以分为两大类&#xff1a;Server层和存储引擎层。Server层&#xff1a; Server层涵盖了MySQL大部分核心业务功能&#xff0c;并且所有存储引擎的功能都在这一层实现。存储引擎层&#xff1a;存储引擎有很多&#xff0c;各自有着各自…

Java EE EJB拦截器教程和示例

在此示例中&#xff0c;我们将看到如何在EJB中使用拦截器并使用简单的Web应用程序对其进行测试。 1.简介 顾名思义&#xff0c;当您想拦截对EJB方法的调用时&#xff0c;将使用拦截器。 如果为Bean声明一个拦截器&#xff0c;则每次调用该Bean的方法时&#xff0c;该拦截器的一…

HTML5结合ajax实现文件上传以及进度显示

基于原生html5实现&#xff0c;不需要falsh支持&#xff0c;进度可以自定义显示&#xff0c;控制灵活&#xff0c; 本来打算使用jquery插件进行异步文件上传&#xff0c;比如uploadfy但是需要额外的支持&#xff0c;也有人用iframe模仿异步上传机制&#xff0c;感觉都比较别扭。…

Mac python Tesseract 验证码识别

Tesseract 简介 Tesseract(/tesərkt/) 这个词的意思是"超立方体"&#xff0c;指的是几何学里的四维标准方体&#xff0c;又称"正八胞体"。不过这里要讲的&#xff0c;是一款以其命名的开源 OCR(Optical Character Recognition, 光学字符识别) 软件。 所谓…

构建器模式:适用于代码,适用于测试

我发现生成器设计模式偶尔在代码中有用&#xff0c;但在测试中经常有用。 本文简要概述了该模式&#xff0c;然后介绍了在测试中使用该模式的一个有效示例。 请参阅github中的代码。 生成器模式的背景 根据GoF的书 &#xff0c;构建器设计模式用于“将复杂对象的构造与其表示分…

如何判断html页面停止滚动?

写在开始的话 查遍的文献&#xff0c;没有找到js或者jquery定义好的方法可用&#xff0c;最后迫不得已自己写了个方法。&#xff08;如果哪位同学知道有其他方法&#xff0c;欢迎讨论&#xff09; 代码 var count_index 0;$(window).scroll(function(e) {if(count_index 0) {…

HTML5教程之-文件拖拽功能实现

现在打开优酷的网站我们再观看视频时如果拖动滚动条&#xff0c;页面会自动出现一个小的播放窗口&#xff0c;而这个播放窗口是可以说随便拖拽的。这种对图片或者链接的拖拽效果是怎么实现的&#xff1f;其实用HTML5就很容易实现了&#xff0c;因为HTML5中有个html5中默认对图片…

php 打乱数组顺序_PHP实现大转盘抽奖算法

php中文网最新课程每日17点准时技术干货分享本文通过具体的实例向大家介绍了PHP语言实现大转盘抽奖算法&#xff0c;希望对大家学习PHP抽奖有所帮助。流程&#xff1a;1.拼装奖项数组&#xff1b;2.计算概率&#xff1b;3.返回中奖情况。代码如下&#xff1a;中奖概率 v 可以…

linux线程基础篇----线程同步与互斥

linux线程基础----线程同步与互斥 一、同步的概念 1.同步概念 所谓同步&#xff0c;即同时起步&#xff0c;协调一致。不同的对象&#xff0c;对“同步”的理解方式略有不同。如&#xff0c;设备同步&#xff0c;是指在两个设备 之间规定一个共同的时间参考&#xff1b;数据库同…

分布式系统开发注意事项

开发分布式软件系统时&#xff0c;要考虑许多因素。 如果您甚至不知道第一句话中我在说什么&#xff0c;那么让我为您提供一些见解&#xff0c;示例以及有关分布式系统的实例。 总览 分布式系统是指多个物理硬件设备与单独的离散用户交互并通过这些硬件设备协作以为这些离散的…