在JPA 2.1中使用@Convert正确完成映射枚举
如果您曾經在JPA中使用過Java枚舉,那么您肯定會意識到它們的局限性和陷阱。 使用enum作為@Entity的屬性通常是一個很好的選擇,但是2.1之前的JPA不能很好地處理它們。 它給了您2 + 1個選擇:
托肖夫達林
幸運的是,幾天前發布的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;//... }其中Cover是enum :
public enum Cover {PAPERBACK, HARDCOVER, DUST_JACKET}ORDINAL和STRING都不是一個很好的選擇。 前者是因為以任何方式重新排列前三個值都會破壞現有記錄的加載。 后者太冗長。 這是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.BigDecimal , scala.Option或小寫類。 在Java中,最終將有一種可移植的方式來映射Joda時間 。 最后但并非最不重要的一點是,如果您喜歡(非常)強類型的域,則可能希望擁有PhoneNumber類(帶有isInternational() , getCountryCode()和自定義驗證邏輯),而不是String或long 。 JPA 2.1中的這一小增加肯定會顯著提高域對象的質量。
如果您想使用此功能, 可以在GitHub上找到示例Spring Web應用程序。
翻譯自: https://www.javacodegeeks.com/2013/06/mapping-enums-done-right-with-convert-in-jpa-2-1.html
總結
以上是生活随笔為你收集整理的在JPA 2.1中使用@Convert正确完成映射枚举的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 茅台真假的识别方法(茅台酒真假鉴别方法图
- 下一篇: 童子功是什么意思(练成“童子功”都有哪些