邊城愚人

          如果我不在邊城,我一定是在前往邊城的路上。

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            31 隨筆 :: 0 文章 :: 96 評論 :: 0 Trackbacks
          ?? ?Hibernate提供客戶化映射類型接口,使用戶能以編程方式創(chuàng)建自定義的映射類型來將持久化類任意類型的屬性映射到數(shù)據(jù)庫中。使用客戶化映射類型,需要實現(xiàn)org.hibernate.usertype.UserType接口。這是個強(qiáng)大的功能,也是Hibernate的最佳實踐之一。我們經(jīng)常提到ORM中很困難的一點便是O的屬性和R的屬性不能一一映射,而Hibernate提供的UserType無疑給出了一個很好的解決方案。本文給出使用客戶化映射類型的兩個例子,算是對Hibernate初學(xué)者的拋磚。
          ?? ?第一個例子是使用UserType映射枚舉類型。假設(shè)Account表中含有一sex列,類型為tinyint(當(dāng)前其0代表男,1代表女,將來可能出現(xiàn)2等代表其他性別類型);我們當(dāng)然可以在對應(yīng)的Account類中添加int類型的sex屬性,但這種數(shù)字化無顯示意義且類型不安全的枚舉不是很好的解決方式,這里就采用了java5的enum來作為Account類的性別屬性(如果不熟悉java5的enum,也可采用《effective java》中提到的經(jīng)典的類型安全的枚舉方案)。在Account添加enum Gender:

          public?class?Account?extends?AbstractDomain<Long>{
          ????
          ????
          public?enum?Gender{
          ????????Male(
          "male",0),
          ????????Female(
          "female",1);
          ????????
          ????????
          private?String?name;
          ????????
          private?int?value;
          ????????
          ????????
          public?String?getName()?{
          ????????????
          return?name;
          ????????}
          ????????
          public?int?getValue()?{
          ????????????
          return?value;
          ????????}
          ????????
          ????????
          private?Gender(String?name,int?value){
          ????????????
          this.name?=?name;
          ????????????
          this.value?=?value;
          ????????}
          ????????
          ????????
          public?static?Gender?getGender(int?value){
          ????????????
          if(0?==?value)return?Male;
          ????????????
          else?if(1?==?value)return?Female;
          ????????????
          else?throw?new?RuntimeException();
          ????????}
          ????????
          ????}
          ????
          ????
          private?Gender?gender;
          ????
          public?Gender?getGender()?{
          ????????
          return?gender;
          ????}
          ????
          public?void?setGender(Gender?gender)?{
          ????????
          this.gender?=?gender;
          ????}
          ???????
          //省略其他????
          }

          ?? ?接下來定義實現(xiàn)UserType接口的GenderUserType:

          public?class?GenderUserType?implements?UserType{

          ????
          public?Object?assemble(Serializable?arg0,?Object?arg1)?throws?HibernateException?{
          ????????
          return?null;
          ????}

          ????
          /*
          ?????*??這是用于Hibernate緩存生成的快照,由于Gender是不可變的,直接返回就好了。
          ?????
          */
          ????
          public?Object?deepCopy(Object?arg0)?throws?HibernateException?{
          ????????
          return?arg0;
          ????}

          ????
          public?Serializable?disassemble(Object?arg0)?throws?HibernateException?{
          ????????
          return?null;
          ????}

          ????
          /*
          ?????*?由于Gender是不可變的,因此直接==了,這個方法將在insert、update時用到。
          ?????
          */
          ????
          public?boolean?equals(Object?x,?Object?y)?throws?HibernateException?{
          ????????
          return?x?==?y;
          ????}

          ????
          public?int?hashCode(Object?o)?throws?HibernateException?{
          ????????
          return?o.hashCode();
          ????}

          ????
          /*
          ?????*?表明Gender是不是可變類(很重要的概念哦),這里的Gender由于是枚舉所以是不可變的
          ?????
          */
          ????
          public?boolean?isMutable()?{
          ????????
          return?false;
          ????}

          ????
          /*
          ?????*??從ResultSet讀取sex并返回Gender實例,這個方法是在從數(shù)據(jù)庫查詢數(shù)據(jù)時用到。
          ?????
          */
          ????
          public?Object?nullSafeGet(ResultSet?rs,?String[]?names,?Object?owner)?throws?HibernateException,?SQLException?{
          ????????
          int?value?=?rs.getInt(names[0]);
          ????????
          return?Account.Gender.getGender(value);
          ????}

          ????
          /*
          ?????*??將Gender的value設(shè)置到PreparedStatement。
          ?????
          */
          ????
          public?void?nullSafeSet(PreparedStatement?ps,?Object?value,?int?index)?throws?HibernateException,?SQLException?{
          ??????? if(value == null){
          ??? ??? ??? ps.setInt(index,Account.Gender.Male.getValue());
          ??? ??? }else{
          ??? ??? ??? ps.setInt(index,((Account.Gender)value).getValue());
          ??? ??? }

          ????}

          ????
          public?Object?replace(Object?arg0,?Object?arg1,?Object?arg2)?throws?HibernateException?{
          ????????
          return?null;
          ????}

          ????
          /*
          ?????*?設(shè)置映射的Gender類
          ?????
          */
          ????
          public?Class?returnedClass()?{
          ????????
          return?Account.Gender.class;
          ????}

          ????
          /*
          ?????*??設(shè)置Gender枚舉中的value屬性對應(yīng)的Account表中的sex列的SQL類型
          ?????
          */
          ????
          public?int[]?sqlTypes()?{
          ????????
          int[]?typeList?=?{Types.TINYINT};
          ????????
          return?typeList;
          ????}
          }

          ?? ?最后在Account的配置文件中配置gender屬性就好了:
          <property name="gender" type="org.prague.domain.util.GenderUserType" column="sex"></property>
          ?? ?除了可以使用 UserType映射枚舉類型,也可以使用Hibernate的PersistentEnum來實現(xiàn)同樣的功能,感興趣的朋友可以參考文章http://www.hibernate.org/203.html。

          ?? ?
          ?? ?第二個例子是關(guān)于email的。假設(shè)Account表中email是一個varchar型的字段,而Account中的Email是如下的類:

          public?class?Email?{
          ????String?username;

          ????String?domain;

          ????
          public?Email()?{
          ????}

          ????
          public?Email(String?username,?String?domain)?{
          ????????
          this.username?=?username;
          ????????
          this.domain?=?domain;
          ????}

          ????
          public?String?getUsername()?{
          ????????
          return?username;
          ????}

          ????
          public?String?getDomain()?{
          ????????
          return?domain;
          ????}

          ????
          ????
          public?void?setDomain(String?domain)?{
          ????????
          this.domain?=?domain;
          ????}

          ????
          public?void?setUsername(String?username)?{
          ????????
          this.username?=?username;
          ????}

          ????
          public?String?toString()?{
          ????????
          return?username?+?'@'?+?domain;
          ????}

          ????
          public?static?Email?parse(String?email)?{
          ????????Email?e?
          =?new?Email();
          ????????
          int?at?=?email.indexOf('@');
          ????????
          if?(at?==?-1)?{
          ????????????
          throw?new?IllegalArgumentException("Invalid?email?address");
          ????????}

          ????????e.username?
          =?email.substring(0,?at);
          ????????e.domain?
          =?email.substring(at?+?1);

          ????????
          return?e;
          ????}

          ????@Override
          ????
          public?int?hashCode()?{
          ????????
          final?int?PRIME?=?31;
          ????????
          int?result?=?1;
          ????????result?
          =?PRIME?*?result?+?((domain?==?null)???0?:?domain.hashCode());
          ????????result?
          =?PRIME?*?result?+?((username?==?null)???0?:?username.hashCode());
          ????????
          return?result;
          ????}

          ????@Override
          ????
          public?boolean?equals(Object?obj)?{
          ????????
          if?(this?==?obj)????return?true;
          ??????
          if(null?==?obj)return?false;
          ????????
          if?(getClass()?!=?obj.getClass())
          ????????????
          return?false;
          ????????
          final?Email?other?=?(Email)?obj;
          ????????
          if?(domain?==?null)?{
          ????????????
          if?(other.domain?!=?null)
          ????????????????
          return?false;
          ????????}?
          else?if?(!domain.equals(other.domain))
          ????????????
          return?false;
          ????????
          if?(username?==?null)?{
          ????????????
          if?(other.username?!=?null)
          ????????????????
          return?false;
          ????????}?
          else?if?(!username.equals(other.username))
          ????????????
          return?false;
          ????????
          return?true;
          ????}
          }
          ????email是Account類的一個屬性:
          public?class?Account?extends?AbstractDomain<Long>{
          ????
          ????
          private?Email?email;
          ????
          public?Email?getEmail()?{
          ????????
          return?email;
          ????}
          ????
          public?void?setEmail(Email?email)?{
          ????????
          this.email?=?email;
          ????}

          ????
          //省略其他????
          }

          ?? ?這樣的情況下,需要將email的username + '@' + domain映射到Account表的email列,定義一個EmailUserType如下:
          ?
          ???public?class?EmailUserType?implements?UserType{

          ????
          public?Object?assemble(Serializable?arg0,?Object?arg1)?throws?HibernateException?{
          ????????
          return?null;
          ????}

          ????
          public?Object?deepCopy(Object?o)?throws?HibernateException?{
          ????????
          if(null?==?o)return?null;
          ????????Email?e?
          =?(Email)o;
          ????????
          return?new?Email(e.getUsername(),e.getDomain());
          ????}

          ????
          public?Serializable?disassemble(Object?arg0)?throws?HibernateException?{
          ????????
          return?null;
          ????}

          ????
          public?boolean?equals(Object?x,?Object?y)?throws?HibernateException?{
          ????????
          if(x?==?y)return?true;
          ????????
          if(x?==?null?||?y?==?null)return?false;
          ????????
          boolean??f?=?x.equals(y);
          ????????
          return?f;
          ????}

          ????
          public?int?hashCode(Object?o)?throws?HibernateException?{
          ????????
          return?o.hashCode();
          ????}

          ????
          public?boolean?isMutable()?{
          ????????
          return?true;
          ????}

          ????
          public?Object?nullSafeGet(ResultSet?rs,?String[]?names,?Object?o)?throws?HibernateException,?SQLException?{
          ????????String?email?
          =?rs.getString(names[0]);
          ????????
          if(email?==?null)return?null;
          ????????
          int?index?=?email.indexOf("@");
          ????????
          if(index?<?0)throw?new?RuntimeException();
          ????????
          return?new?Email(email.substring(0,index),email.substring(index+1));
          ????}

          ????
          public?void?nullSafeSet(PreparedStatement?ps,?Object?o,?int?index)?throws?HibernateException,?SQLException?{
          ????????
          if(o?==?null?)ps.setNull(index,?Types.VARCHAR);
          ????????
          else{
          ????????????Email?e?
          =?(Email)o;
          ????????????
          if(e.getDomain()?==?null?||?e.getUsername()?==?null)ps.setNull(index,?Types.VARCHAR);
          ????????????
          else{
          ????????????????String?email?
          =?e.getUsername()?+?"@"?+?e.getDomain();
          ????????????????ps.setString(index,?email);
          ????????????}
          ????????}
          ????????
          ????}

          ????
          public?Object?replace(Object?arg0,?Object?arg1,?Object?arg2)?throws?HibernateException?{
          ????????
          return?null;
          ????}

          ????
          public?Class?returnedClass()?{
          ????????
          return?Email.class;
          ????}

          ????
          public?int[]?sqlTypes()?{
          ????????
          int[]?typeList?=?{Types.VARCHAR};
          ????????
          return?typeList;
          ????}
          }

          ?? ?最后配置下 email 屬性:
          <property name="email" type="org.prague.domain.util.EmailUserType" column="email"></property>
          ?? ?相比于Gedner,Email是一個可變類(如果想將其變?yōu)椴豢勺冾悾恍枰サ魧傩缘膕et方法),因此EmailUserType中的equals要用到Email的equals(hashCode())方法,而deepCopy(Object o) 要做到是深拷貝,否則即便Email屬性內(nèi)容改變,由于Hibernate緩存中的快照指向的對象不變,在update時可能不起作用(在指定了dynamic-update屬性的清況下)。
          ?? ?

          posted on 2007-08-15 10:32 kafka0102 閱讀(1527) 評論(0)  編輯  收藏 所屬分類: Framework
          主站蜘蛛池模板: 建平县| 新丰县| 松原市| 涡阳县| 鄂温| 阿尔山市| 增城市| 淮滨县| 铜山县| 梨树县| 平顺县| 海兴县| 都安| 资阳市| 资源县| 会昌县| 松江区| 麻阳| 旬邑县| 当涂县| 庆城县| 景德镇市| 吐鲁番市| 大荔县| 循化| 姜堰市| 延川县| 平潭县| 襄城县| 富川| 手游| 无为县| 浙江省| 夏津县| 武鸣县| 确山县| 永嘉县| 三河市| 札达县| 花垣县| 栾城县|