摘要:內(nèi)置了轉(zhuǎn)換器,可將枚舉轉(zhuǎn)換為或。接下來需要在中完成對(duì)枚舉的轉(zhuǎn)換。方案提供了接口指定如何將實(shí)體屬性轉(zhuǎn)換為數(shù)據(jù)庫(kù)列表示。此方案適用與數(shù)量不多或者個(gè)別特殊的枚舉。在合并過程中,將正在合并的實(shí)體中的現(xiàn)有目標(biāo)值替換為正在合并的分離實(shí)體的新原始值。
問題
在編碼過程中,經(jīng)常會(huì)遇到用某個(gè)數(shù)值來表示某種狀態(tài)、類型或者階段的情況,比如有這樣一個(gè)枚舉:
public enum ComputerState { OPEN(10), //開啟 CLOSE(11), //關(guān)閉 OFF_LINE(12), //離線 FAULT(200), //故障 UNKNOWN(255); //未知 private int code; ComputerState(int code) { this.code = code; } }
通常我們希望將表示狀態(tài)的數(shù)值存入數(shù)據(jù)庫(kù),即ComputerState.OPEN存入數(shù)據(jù)庫(kù)取值為10。
探索首先,我們先看看Hibernate是否能夠滿足我們的需求。
Hibernate內(nèi)置了org.hibernate.type.EnumType轉(zhuǎn)換器,可將枚舉轉(zhuǎn)換為Named或Ordinal。
這樣使用它:
// 將ComputerState.OPEN轉(zhuǎn)換OPEN @Enumerated(EnumType.STRING) private ComputerState state;
// ComputerState.OPEN轉(zhuǎn)換為0,ComputerState.CLOSE轉(zhuǎn)換為1 @Enumerated(EnumType.STRING) private ComputerState state;
以上的兩種方式不能滿足我們的需求,看起來要自己實(shí)現(xiàn)轉(zhuǎn)換的過程了。
準(zhǔn)備工作首先,我們需要做一些準(zhǔn)備工作,便于在枚舉和code之間轉(zhuǎn)換。
1. 定義接口我們需要一個(gè)接口來確定某部分枚舉類的行為。如下:
public interface BaseCodeEnum { int getCode(); }
該接口只有一個(gè)返回編碼的方法,返回值將被存入數(shù)據(jù)庫(kù)。
2. 改造枚舉就拿上面的ComputerState來實(shí)現(xiàn)BaseCodeEnum接口:
public enum ComputerState implements BaseCodeEnum{ OPEN(10), //開啟 CLOSE(11), //關(guān)閉 OFF_LINE(12), //離線 FAULT(200), //故障 UNKNOWN(255); //未知 private int code; ComputerState(int code) { this.code = code; } @Override public int getCode() { return this.code; } }3. 編寫一個(gè)轉(zhuǎn)換工具類
現(xiàn)在我們能順利的將枚舉轉(zhuǎn)換為某個(gè)數(shù)值了,還需要一個(gè)工具將數(shù)值轉(zhuǎn)換為枚舉實(shí)例。
public class CodeEnumUtil { public static& BaseCodeEnum> E codeOf(Class enumClass, int code) { E[] enumConstants = enumClass.getEnumConstants(); for (E e : enumConstants) { if (e.getCode() == code) return e; } return null; } }
至此,準(zhǔn)備工作完成。接下來需要在Hibernate中完成對(duì)枚舉的轉(zhuǎn)換。
方案1:AttributeConverterHibernate提供了javax.persistence.AttributeConverter
此方案適用與數(shù)量不多或者個(gè)別特殊的枚舉。
需要實(shí)現(xiàn)兩個(gè)方法:
public Y convertToDatabaseColumn (X attribute);
該方法指定如何將實(shí)體屬性轉(zhuǎn)換為數(shù)據(jù)庫(kù)列屬性
public X convertToEntityAttribute (Y dbData);
該方法指定如何將數(shù)據(jù)庫(kù)列屬性轉(zhuǎn)換為實(shí)體屬性
我是這樣實(shí)現(xiàn)的:
public class CodeEnumConverter implements AttributeConverter{ @Override public Integer convertToDatabaseColumn(ComputerState attribute) { return attribute.getCode(); } @Override public ComputerState convertToEntityAttribute(Integer dbData) { return CodeEnumUtil.codeOf(ComputerState.class,dbData); } }
這樣使用:
@Convert( converter = CodeEnumConverter.class ) private ComputerState state;方案2:UserType
除了AttributeConverter還提供了一個(gè)用戶自定義類型的接口:org.hibernate.usertype.UserType。
注意! 這里的類型不是一個(gè)實(shí)際的屬性類型,而是一個(gè)知道如何將數(shù)據(jù)類型序列化到JDBC的類!
此方案適用于具有相似行為的一組枚舉。
需要實(shí)現(xiàn)以下方法:
public int[] sqlTypes()
返回由該類型映射列的SQL類型代碼。
public Class returnedClass()
指定由SQL類型轉(zhuǎn)換成哪種數(shù)據(jù)類型
public boolean equals(Object x, Object y) throws HibernateException;
數(shù)據(jù)類型之間的比對(duì)
public int hashCode(Object x) throws HibernateException;
將數(shù)據(jù)類型轉(zhuǎn)換為HashCode
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException;
從JDBC ResultSet讀取數(shù)據(jù),將其轉(zhuǎn)換為數(shù)據(jù)類型后返回,需要處理NULL值。
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException;
將數(shù)據(jù)類型轉(zhuǎn)換為SQL類型
public Object deepCopy(Object value) throws HibernateException;
深度拷貝
public boolean isMutable();
類型是否可變
public Serializable disassemble(Object value) throws HibernateException;
將對(duì)象轉(zhuǎn)換為可緩存的表示形式
public Object assemble(Serializable cached, Object owner) throws HibernateException;
從緩存中重建一個(gè)對(duì)象。
public Object replace(Object original, Object target, Object owner) throws HibernateException;
在合并過程中,將正在合并的實(shí)體中的現(xiàn)有(目標(biāo))值替換為正在合并的分離實(shí)體的新(原始)值。
我是這樣實(shí)現(xiàn)的(參考了org.hibernate.type.EnumType):
public class CodeEnumType& BaseCodeEnum> implements UserType, DynamicParameterizedType { private static final int SQL_TYPE = Types.INTEGER; private static final String ENUM = "enumClass"; private Class enumClass; @Override public void setParameterValues(Properties parameters) { final ParameterType reader = (ParameterType) parameters.get(PARAMETER_TYPE); if (reader != null) { enumClass = reader.getReturnedClass().asSubclass(Enum.class); } else { final String enumClassName = (String) parameters.get(ENUM); try { enumClass = ReflectHelper.classForName(enumClassName, this.getClass()).asSubclass(Enum.class); } catch (ClassNotFoundException exception) { throw new HibernateException("Enum class not found: " + enumClassName, exception); } } } @Override public int[] sqlTypes() { return new int[]{SQL_TYPE}; } @Override public Class returnedClass() { return enumClass; } @Override public boolean equals(Object x, Object y) throws HibernateException { return x == y; } @Override public int hashCode(Object x) throws HibernateException { return x == null ? 0 : x.hashCode(); } @Override public E nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { final int value = rs.getInt(names[0]); return rs.wasNull() ? null : codeOf(value); } @Override public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { st.setObject(index, ((BaseCodeEnum) value).getCode(), SQL_TYPE); } @Override public Object deepCopy(Object value) throws HibernateException { return value; } @Override public boolean isMutable() { return false; } @Override public Serializable disassemble(Object value) throws HibernateException { return (Serializable) value; } @Override public Object assemble(Serializable cached, Object owner) throws HibernateException { return cached; } @Override public Object replace(Object original, Object target, Object owner) throws HibernateException { return original; } private E codeOf(int code) { try { return CodeEnumUtil.codeOf(enumClass, code); } catch (Exception ex) { throw new IllegalArgumentException("Cannot convert " + code + " to " + enumClass.getSimpleName() + " by code value.", ex); } } }
其中實(shí)現(xiàn)了DynamicParameterizedType.setParameterValues方法,是為了獲取具體的子類。
這樣使用:
@Type(type = "com.example.CodeEnumType") private ComputerState state;結(jié)束了
好久沒有摸Hibernate了,生疏了很多。如果你還有更優(yōu)的解決方案,請(qǐng)一定在評(píng)論中告知,萬分感激。
在Mybatis中使用枚舉可以看這里
參考資料:
Hibernate User Guide
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68440.html
摘要:本文速覽本篇文章是我為接下來的源碼分析系列文章寫的一個(gè)導(dǎo)讀文章。年該項(xiàng)目從基金會(huì)遷出,并改名為。同期,停止維護(hù)。符號(hào)所在的行則是表示的執(zhí)行結(jié)果。同時(shí),使用無需處理受檢異常,比如。另外,把寫在配置文件中,進(jìn)行集中管理,利于維護(hù)。 1.本文速覽 本篇文章是我為接下來的 MyBatis 源碼分析系列文章寫的一個(gè)導(dǎo)讀文章。本篇文章從 MyBatis 是什么(what),為什么要使用(why),...
摘要:自帶對(duì)枚舉的處理類該類實(shí)現(xiàn)了枚舉類型和類型的相互轉(zhuǎn)換。而在具體中也需要使用屬性,如在處理到該位置時(shí),就會(huì)調(diào)用指定的處理類來處理枚舉類型。 mybatis自帶對(duì)枚舉的處理類 org.apache.ibatis.type.EnumOrdinalTypeHandler :該類實(shí)現(xiàn)了枚舉類型和Integer類型的相互轉(zhuǎn)換。 但是給轉(zhuǎn)換僅僅是將對(duì)應(yīng)的枚舉轉(zhuǎn)換為其索引位置,也就是ordinal(...
摘要:如何解決呢在中我們可以使用方式來干預(yù)的創(chuàng)建過程,來完成轉(zhuǎn)換器的指定。再也不用寫的配置文件了結(jié)束了以上就是我對(duì)如何在中優(yōu)雅的使用枚舉的探索。 問題 在編碼過程中,經(jīng)常會(huì)遇到用某個(gè)數(shù)值來表示某種狀態(tài)、類型或者階段的情況,比如有這樣一個(gè)枚舉: public enum ComputerState { OPEN(10), //開啟 CLOSE(11), ...
摘要:在接口服務(wù)開發(fā)中,難免會(huì)校驗(yàn)傳入方的參數(shù)校驗(yàn),尤其在請(qǐng)求時(shí),驗(yàn)證字符長(zhǎng)度,字符類型是否滿足數(shù)據(jù)庫(kù)中字段的最大長(zhǎng)度及類型,如果不符合條件應(yīng)及時(shí)攔截并返回,避免后續(xù)的流程。 showImg(https://segmentfault.com/img/remote/1460000018664784); 公司轉(zhuǎn)java開發(fā)也有一段時(shí)間了,在實(shí)際開發(fā)過程中還是會(huì)遇到一些問題的,本篇主要記錄下接口服...
摘要:結(jié)構(gòu)型模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。行為型模式模版方法模式命令模式迭代器模式觀察者模式中介者模式備忘錄模式解釋器模式模式狀態(tài)模式策略模式職責(zé)鏈模式責(zé)任鏈模式訪問者模式。 主要版本 更新時(shí)間 備注 v1.0 2015-08-01 首次發(fā)布 v1.1 2018-03-12 增加新技術(shù)知識(shí)、完善知識(shí)體系 v2.0 2019-02-19 結(jié)構(gòu)...
閱讀 1667·2021-09-26 09:55
閱讀 5289·2021-09-22 15:40
閱讀 2027·2019-08-30 15:53
閱讀 1508·2019-08-30 11:15
閱讀 1725·2019-08-29 15:41
閱讀 1879·2019-08-28 18:13
閱讀 3159·2019-08-26 12:00
閱讀 1681·2019-08-26 10:30