JPA实现自定义类型(二)

今天继续昨天的内容,JPA实现一个自定义类型,昨天我们说了怎么实现一个基本类型,今天学习一个复杂一点的。

我们的用例场景是将一个领域对象映射到一个类型,比如有一个PhoneNumber的对象,它包含三个字段分别是countryCode,cityCode,number,现在需要将这个对象映射到数据库,我们看怎么来实现:

第一步,创建一个PhoneNumber

public class PhoneNumber {
    private Integer countryCode;

    private Integer cityCode;

    private Integer number;

    public PhoneNumber(){}
    public PhoneNumber(Integer countryCode,
                       Integer cityCode,
                       Integer number){
        this.countryCode = countryCode;
        this.cityCode = cityCode;
        this.number = number;
    }


    public Integer getCountryCode() {
        return countryCode;
    }

    public void setCountryCode(Integer countryCode) {
        this.countryCode = countryCode;
    }

    public Integer getCityCode() {
        return cityCode;
    }

    public void setCityCode(Integer cityCode) {
        this.cityCode = cityCode;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }
}

第二步,创建一个PhoneNumberType

public class PhoneNumberType implements UserType {
    @Override
    public int[] sqlTypes() {
        return new int[]{Types.INTEGER, Types.INTEGER, Types.INTEGER};
    }

    @Override
    public boolean equals(Object o, Object o1) throws HibernateException {
        return false;
    }

    @Override
    public int hashCode(Object o) throws HibernateException {
        return 0;
    }

    @Override
    public Object nullSafeGet(ResultSet resultSet, String[] names,
                              SharedSessionContractImplementor sharedSessionContractImplementor,
                              Object o) throws HibernateException, SQLException {
        if (resultSet.wasNull())
            return null;
        int countryCode = resultSet.getInt(names[0]);
        int cityCode = resultSet.getInt(names[1]);
        int number = resultSet.getInt(names[2]);
        PhoneNumber employeeNumber = new PhoneNumber(countryCode, cityCode, number);

        return employeeNumber;
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor sharedSessionContractImplementor) throws HibernateException, SQLException {
        if (Objects.isNull(value)) {
            st.setNull(index, Types.INTEGER);
            st.setNull(index + 1, Types.INTEGER);
            st.setNull(index + 2, Types.INTEGER);
        } else {
            PhoneNumber employeeNumber = (PhoneNumber) value;
            st.setInt(index,employeeNumber.getCountryCode());
            st.setInt(index+1,employeeNumber.getCityCode());
            st.setInt(index+2,employeeNumber.getNumber());
        }
    }

    @Override
    public Object deepCopy(Object o) throws HibernateException {
        return null;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object o) throws HibernateException {
        return null;
    }

    @Override
    public Object assemble(Serializable serializable, Object o) throws HibernateException {
        return null;
    }

    @Override
    public Object replace(Object o, Object o1, Object o2) throws HibernateException {
        return null;
    }

    @Override
    public Class returnedClass() {
        return PhoneNumber.class;
    }
}

在这里,重写的 sqlTypes 方法返回字段的 SQL 类型,顺序与它们在我们的 PhoneNumber 类中声明的顺序相同。同样,returnedClass 方法返回我们的 PhoneNumber Java 类型。

唯一剩下要做的就是实现在 Java 类型和 SQL 类型之间转换的方法,就像我们为 BasicType 所做的那样。

关键就是实现nullSafeSetnullSafeGet两个方法,它的基本原理就是设置PreparedStatement的值,以及从ResultSet中取出值来创建Java对象;

注意,在这里我们实现的是UserType接口,也许您有的疑问是为什么不用@Embeddable 其实都是可以使用的,但是这里用UserType的原因是如果有需要自定义的情况,还是建议您使用UserType,否则还是使用@Embeddable ;

在具体使用的时候,需要这样配置:

@Type(type = "com.jpa.demo.custom.type.PhoneNumberType")
@Columns(columns = { @Column(name = "country_code"),
        @Column(name = "city_code"), @Column(name = "number") })
private PhoneNumber employeeNumber;

好啦,欢迎讨论。

 

版权声明:著作权归作者所有。

thumb_up 0 | star_outline 0 | textsms 0