2015年11月14日 星期六

客製化型態轉換 (Hibernate3.x 十九)

假設前端有個叫興趣的checkbox,那傳到後端用List來接好了,但存進資料庫想用「,」隔開的方式儲存,且取出來時又要變成List,這時就可以用以下的方法,官方有三種,這裡介紹其中一種

※準備資料

CREATE TABLE INDIVISUAL_FILE(
    ID NUMBER(5),
    NAME VARCHAR(10),
    INTEREST VARCHAR(120),
    CONSTRAINT PK_INDIVISUAL_FILE PRIMARY KEY(ID)
);

※INTEREST設大一個,因為有很多興趣


※UserType

先寫一個class,繼承UserType,總共要覆寫11個方法
public class InterestUserType implements UserType {
    
    @Override
    public int[] sqlTypes() {
        System.out.println("sqlTypes");
        return new int[] { Types.VARCHAR };
    }
    
    @Override
    public Class<?> returnedClass() {
        System.out.println("returnedClass");
        return List.class;
    }
    
    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        System.out.println("equals");
        if (x == null || y == null) {
            return false;
        }
        if (x == y) {
            return true;
        }
        return x.equals(y);
    }
    
    @Override
    public int hashCode(Object x) throws HibernateException {
        System.out.println("hashCode");
        return x.hashCode();
    }
    
    /**
     * 從資料庫取出
     */
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
            throws HibernateException, SQLException {
        System.out.println("nullSafeGet");
        return this.disassemble(rs.getString(names[0]));
    }
    
    /**
     * 存到資料庫
     */
    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index)
            throws HibernateException, SQLException {
        System.out.println("nullSafeSet");
        if (value == null) {
            st.setNull(index, java.sql.Types.NULL);
        } else {
            st.setString(index, this.assemble(null, value).toString());
        }
    }
    
    /**
     * 複製原始資料
     */
    @SuppressWarnings("unchecked")
    @Override
    public Object deepCopy(Object value) throws HibernateException {
        System.out.println("deepCopy");
        if (value == null) {
            return null;
        }
        List<String> newData = new ArrayList<String>();
        newData.addAll((List<String>) value);
        return newData;
    }
    
    /**
     * 此實體是否可被改變
     */
    @Override
    public boolean isMutable() {
        System.out.println("isMutable");
        return true;
    }
    
    /**
     * 將「,」轉成List
     */
    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        System.out.println("disassemble");
        List<String> list = new ArrayList<String>();
        String comma[] = value.toString().split(",");
        for (int i = 0; i < comma.length; i++) {
            list.add(comma[i]);
        }
        return (Serializable) list;
    }
    
    /**
     * 將List轉成「,」的型式
     */
    @Override
    public Object assemble(Serializable cached, Object owner)
            throws HibernateException {
        System.out.println("assemble");
        StringBuffer sb = new StringBuffer();

        @SuppressWarnings("unchecked")
        Iterator<String> it = ((List<String>) owner).iterator();
        while (it.hasNext()) {
            sb.append(it.next()).append(",");
        }
        return sb;
    }
    
    @Override
    public Object replace(Object original, Object target, Object owner)
            throws HibernateException {
        System.out.println("replace");
        return original;
    }
}

※XML設定

IndivisualFile.java

public class IndivisualFile {
    private Integer id;
    private String name;
    private List<String> interest;
    //setter/getter...
}

IndivisualFile.hbm.xml

<class name="vo.IndivisualFile" table="INDIVISUAL_FILE">
    <id name="id" type="java.lang.Integer">
        <column name="ID" />
        <generator class="assigned" />
    </id>
    
    <property name="name" type="java.lang.String">
        <column name="NAME" />
    </property>
    
    <property name="interest" type="vo.InterestUserType">
        <column name="INTEREST" />
    </property>
</class>

※注意interest的type要連到前面寫的InterestUserType

測試類

Session s = HibernateUtil2.getSession();
Transaction tx = s.beginTransaction();
try {
    IndivisualFile idv = new IndivisualFile();
    idv.setId(1);
    idv.setName("王小明");
    idv.setInterest(new ArrayList<String>());
    idv.getInterest().add("下棋");
    idv.getInterest().add("爬山");
    idv.getInterest().add("聽音樂");
    s.save(idv);
    tx.commit();
    
    IndivisualFile rtn = (IndivisualFile) s.get(IndivisualFile.class, 1);
    System.out.println("id:" + rtn.getId());
    System.out.println("name:" + rtn.getName());
    System.out.println("size:" + rtn.getInterest().size());
    for (String str : rtn.getInterest()) {
        System.out.println(str);
    }
} catch (Exception e) {
    System.err.println("例外錯誤!");
    e.printStackTrace();
    tx.rollback();
} finally {
    if (s.isOpen()) {
        s.close();
    }
}

控制台的執行結果:
sqlTypes
sqlTypes
sqlTypes
isMutable
sqlTypes
sqlTypes
sqlTypes
sqlTypes
deepCopy
equals
Hibernate:
    insert
    into
        INDIVISUAL_FILE
        (NAME, INTEREST, ID)
    values
        (?, ?, ?)
nullSafeSet
assemble
id:1
name:王小明
size:3
下棋
爬山
聽音樂

※而資料庫的INTEREST欄位是:下棋,爬山,聽音樂,
最後有個逗點,但無所謂,取出時大小還是3



※Annotation設定

IndivisualFile.java

@Entity
@Table(name = "INDIVISUAL_FILE")
public class IndivisualFile {
    private Integer id;
    private String name;
    private List<String> interest;
    
    @Id
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @Type(type = "vo.InterestUserType")
    public List<String> getInterest() {
        return interest;
    }
    
    public void setInterest(List<String> interest) {
        this.interest = interest;
    }
}


沒有留言:

張貼留言