实现自定义hibernate类型

时间:2016-02-05 15:39:15

标签: java oracle hibernate custom-type

我正在尝试将hibernate映射实现为Oracle默认安装提供的示例模式(Order Entry) orderentry模式有几个表,其中一个是Customer表,例如,有少量列作为customTyped列 使用以下语句创建自定义类型;

CREATE OR REPLACE TYPE "CUST_ADDRESS_TYP"  AS OBJECT
( street_address     VARCHAR2(40)
, postal_code        VARCHAR2(10)
, city               VARCHAR2(30)
, state_province     VARCHAR2(10)
, country_id         CHAR(2)
);

并使用以下语句

创建customer表
CREATE TABLE OE.CUSTOMERS 
( 
 CUSTOMER_ID NUMBER (6)  NOT NULL , 
 CUST_FIRST_NAME VARCHAR2 (20 BYTE) 
 CONSTRAINT CUST_FNAME_NN NOT NULL , 
 CUST_LAST_NAME VARCHAR2 (20 BYTE) 
 CONSTRAINT CUST_LNAME_NN NOT NULL , 
 CUST_ADDRESS OE.CUST_ADDRESS_TYP , 
 )

我发现我们需要从here实现UserType接口,但是当我尝试检索它时会发出错误

 org.hibernate.MappingException: property mapping has wrong number of columns: com.dto.oe.Customers.cust_addressData type: com.dto.oe.CustAddressType
            at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:497)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1360)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1930)
at com.test.connection.HibernateUtil.getSession(HibernateUtil.java:82)
at com.test.connection.HibernateUtil.getCustomer(HibernateUtil.java:70)
at com.test.connection.HibernateUtil.main(HibernateUtil.java:18)

我的Customtype对象pojo类是Cust_addressData,实现usertype接口的类是CustAddressType

    import java.io.Serializable;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Types;

    import org.hibernate.HibernateException;
    import org.hibernate.engine.spi.SessionImplementor;
    import org.hibernate.usertype.UserType;

    public class CustAddressType implements UserType {
    /**
     * Returns the object from the 2 level cache
     */
    public Object assemble(Serializable cached, Object owner)
            throws HibernateException {
        return cached;
    }

    /**
     * Used to create Snapshots of the object
     */
    public Object deepCopy(Object value) throws HibernateException {
        final Cust_addressData recievedParam = (Cust_addressData) value;
        final Cust_addressData addressData = new Cust_addressData(recievedParam);
        return addressData;
    }

    /**
     * method called when Hibernate puts the data in a second level cache. The
     * data is stored in a serializable form
     */
    public Serializable disassemble(final Object value)
            throws HibernateException {
        return (Serializable) value;
    }

    public boolean equals(final Object o1, final Object o2)
            throws HibernateException {
        boolean isEqual = false;
        if (o1 == o2) {
            isEqual = true;
        }
        if (null == o1 || null == o2) {
            isEqual = false;
        } else {
            isEqual = o1.equals(o2);
        }
        return isEqual;
        // for this to work correctly the equals()
        // method must be implemented correctly by Cust_addressData class
    }

    public int hashCode(final Object arg0) throws HibernateException {
        return arg0.hashCode();
    }

    public boolean isMutable() {
        return true;
    }

    public Object nullSafeGet(final ResultSet resultSet, final String[] names,
            SessionImplementor sessionImp, final Object owner)
            throws HibernateException, SQLException {

        // owner here is class from where the call to retrieve data was made.
        // In this case the Test class

        Cust_addressData addresssData = new Cust_addressData();
        // Order of columns is given by sqlTypes() method
        if (!resultSet.wasNull()) {


            final String street_address = resultSet.getString(names[0]);
            final String postal_code = resultSet.getString(names[1]);
            final String city = resultSet.getString(names[2]);
            final String state_province = resultSet.getString(names[3]);
            final String country_id = resultSet.getString(names[4]);

            addresssData.setCity(city);
            addresssData.setCountry_id(country_id);
            addresssData.setPostal_code(postal_code);
            addresssData.setState_province(state_province);
            addresssData.setStreet_address(street_address);
            System.out.println("street_address "+street_address +"  names  "+names[0]);
        } else {
            System.err.println("resultSet is null in CustAddressType");
        }
        return addresssData;
    }

    public void nullSafeSet(final PreparedStatement statement, final Object value, final int index,
            SessionImplementor arg3) throws HibernateException, SQLException {
        if (null == value) {
            statement.setNull(index, Types.VARCHAR);
            statement.setNull(index + 1, Types.VARCHAR);
            statement.setNull(index + 2, Types.VARCHAR);
            statement.setNull(index + 3,Types.VARCHAR);
            statement.setNull(index + 4,Types.VARCHAR);
        } else {
            Cust_addressData addressData = (Cust_addressData) value;

            if (null != addressData.getStreet_address()) {
                String  street_address = new String(addressData.getStreet_address());
                statement.setString(index , street_address);
            } else {
                statement.setNull(index , Types.VARCHAR);
            }

            if (null != addressData.getPostal_code()) {
                 String  postal_Code = new String(addressData.getPostal_code());
                 statement.setString(index+1 , postal_Code);
            } else {
                statement.setNull(index +1, Types.VARCHAR);
            }

            if (null != addressData.getCity()) {
             String  city = new String(addressData.getCity());
                statement.setString(index+2 , city);
           } else {
               statement.setNull(index +2, Types.VARCHAR);
           }

            if (null != addressData.getState_province()) {
             String  postal_Code = new String(addressData.getState_province());
                statement.setString(index+3 , postal_Code);
           } else {
               statement.setNull(index +3, Types.VARCHAR);
           }


            if (null != addressData.getCountry_id()) {
             String  postal_Code = new String(addressData.getCountry_id());
                statement.setString(index+4 , postal_Code);
           } else {
               statement.setNull(index +4, Types.VARCHAR);
           }

        }

    }

    public Object replace(final Object original, final Object target,
            final Object owner) throws HibernateException {
        return this.deepCopy(original);
    }

    @SuppressWarnings("rawtypes")
    public Class returnedClass() {
        return Cust_addressData.class;
    }

    public int[] sqlTypes() {
        return new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
                Types.VARCHAR, Types.VARCHAR };
    }
}
     import java.io.Serializable;
     import javax.persistence.Column;
     import javax.persistence.Entity;
     import javax.persistence.Table;
    @SuppressWarnings("serial")
    @Entity
    @Table(name="CUST_ADDRESS_TYP")
    public class Cust_addressData implements Serializable {
    /**
     * 
     */
private static final long serialVersionUID = 1L;
    @Column(name = "street_address")
    private String street_address;
    @Column(name = "postal_code")
    private String postal_code;
    @Column(name = "city")
    private String city;
    @Column(name = "state_province")
    private String state_province;
    @Column(name = "country_id")
    private String country_id;

    public Cust_addressData() {
    }

    public Cust_addressData(Cust_addressData other) {
        this.setCity(other.getCity());
        this.setCountry_id(other.getCountry_id());
        this.setPostal_code(other.getPostal_code());
        this.setStreet_address(other.getStreet_address());
        this.setState_province(other.getState_province());

    }

    public String getStreet_address() {
        return street_address;
    }

    public void setStreet_address(String street_address) {
        this.street_address = street_address;
    }

    public String getPostal_code() {
        return postal_code;
    }

    public void setPostal_code(String postal_code) {
        this.postal_code = postal_code;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getState_province() {
        return state_province;
    }

    public void setState_province(String state_province) {
        this.state_province = state_province;
    }

    public String getCountry_id() {
        return country_id;
    }

    public void setCountry_id(String country_id) {
        this.country_id = country_id;
    }

    @Override
    public boolean equals(Object obj) {

        boolean isEqual = false;
        if (obj instanceof Cust_addressData) {
            Cust_addressData addressData = (Cust_addressData) obj;

            isEqual = addressData.getCity().equals(this.getCity())
                    && addressData.getState_province().equals(this.getState_province())
                    && addressData.getCountry_id().equals(this.getCountry_id())
                    && addressData.getPostal_code().equals(this.getPostal_code())
                    && addressData.getStreet_address().equals(this.getStreet_address())
                    ;
        }
        return isEqual;
    }

    @Override
    public int hashCode() {
        int hash = this.getCountry_id().hashCode();
        hash = hash * 17 + this.getPostal_code().hashCode();
        hash = hash * 31 + this.getStreet_address().hashCode();
        hash = hash * 13 + this.getState_province().hashCode();
        hash = hash * 14 + this.getCity().hashCode();
        return hash;
    }

    @Override
    public String toString() {

        return "[ " + this.getClass() + " { city : " + city
                + ", street_address: " + street_address + ", postal_code: "
                + postal_code + ", state_province: " + state_province + ""
                        + ",country_id :"+country_id+"}]";
    }
}

完整资料来源:

另一个观察结果是在CustAddressType类

中的sqlTypes方法
public int[] sqlTypes() {
    return new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
        Types.VARCHAR, Types.VARCHAR };
}

是返回列数的那个,如果我让它只返回一列我将列值变为null。

不确定究竟出了什么问题,任何建议,我做错了或任何线索将不胜感激

2 个答案:

答案 0 :(得分:5)

在我的CustAddressType类中使用STRUCT类解决了CustAddressType类的源代码如下问题。

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Struct;
import java.sql.Types;

import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;

public class CustAddressType implements UserType {
    private static final int SQL_TYPE = Types.STRUCT;
    private static final String OBJECT_TYPE = "CUST_ADDRESS_TYP";
    /**
     * Returns the object from the 2 level cache
     */
    public Object assemble(Serializable cached, Object owner)
        throws HibernateException {
    return cached;
}

/**
 * Used to create Snapshots of the object
 */
public Object deepCopy(Object value) throws HibernateException {
    if (value == null) {
        return null;
    }
    final Cust_addressData recievedParam = (Cust_addressData) value;
    final Cust_addressData addressData = new Cust_addressData(recievedParam);

    return addressData;
}

/**
 * method called when Hibernate puts the data in a second level cache. The
 * data is stored in a serializable form
 */
public Serializable disassemble(final Object value)
        throws HibernateException {
    return (Serializable) value;
}

public boolean equals(final Object o1, final Object o2)
        throws HibernateException {
    boolean isEqual = false;
    if (o1 == o2) {
        isEqual = true;
    }
    if (null == o1 || null == o2) {
        isEqual = false;
    } else {
        isEqual = o1.equals(o2);
    }
    return isEqual;
    // for this to work correctly the equals()
    // method must be implemented correctly by Cust_addressData class
}

public int hashCode(final Object arg0) throws HibernateException {
    return arg0.hashCode();
}

public boolean isMutable() {
    return true;
}

public Object nullSafeGet(final ResultSet resultSet, final String[] names,
        SessionImplementor sessionImp, final Object owner)
        throws HibernateException, SQLException {

    // owner here is class from where the call to retrieve data was made.
    // In this case the Test class

    final Cust_addressData addresssData = new Cust_addressData();

    final Struct struct = (Struct) resultSet.getObject(names[0]);

    if (resultSet.wasNull()) {
        return null;
    }
    addresssData.setCity((String)struct.getAttributes()[0]);
    addresssData.setCountry_id((String)struct.getAttributes()[1]);
    addresssData.setPostal_code((String)struct.getAttributes()[2]);
    addresssData.setState_province((String)struct.getAttributes()[3]);
    addresssData.setStreet_address((String)struct.getAttributes()[4]);

    return addresssData;
}

public void nullSafeSet(final PreparedStatement statement, final Object value, final int index,
        SessionImplementor arg3) throws HibernateException, SQLException {
    if (value == null) {
        statement.setNull(index, SQL_TYPE, OBJECT_TYPE);
    } 
    else {
        final Cust_addressData addresssData = (Cust_addressData) value;
        final Object[] values = new Object[] { addresssData.getCity(),addresssData.getCountry_id(), addresssData.getPostal_code(),
                addresssData.getState_province(),addresssData.getStreet_address() };
        final Connection connection = statement.getConnection();
        final STRUCT struct = new STRUCT(StructDescriptor.createDescriptor( OBJECT_TYPE,connection), connection, values);
        statement.setObject(index, struct, SQL_TYPE);
    }
}

public Object replace(final Object original, final Object target,
        final Object owner) throws HibernateException {
    return this.deepCopy(original);
}

@SuppressWarnings("rawtypes")
public Class returnedClass() {
    return Cust_addressData.class;
}

public int[] sqlTypes() {
    return new int[] {SQL_TYPE};
}
}

感谢 @SteveChambers 指出它,

答案 1 :(得分:0)

我的朋友hibernate Annotations在哪里?你必须清楚地用名称包括你的表名来定义每个字段......

import java.io.Serializable;

@Entity
@Table(name = "CUST_ADDRESS_TYP")
public class Cust_addressData implements Serializable {
/**
 * 
 */
private static final long serialVersionUID = 1L;
  @Column(name ="column_name")
private String street_address;
  @Column(name ="column_name")
private String postal_code;
  @Column(name ="column_name")
private String city;
  @Column(name ="column_name")
private String state_province;
  @Column(name ="column_name")
private String country_id;

public Cust_addressData() {
}

public Cust_addressData(Cust_addressData other) {
    this.setCity(other.getCity());
    this.setCountry_id(other.getCountry_id());
    this.setPostal_code(other.getPostal_code());
    this.setStreet_address(other.getStreet_address());
    this.setState_province(other.getState_province());

}

public String getStreet_address() {
    return street_address;
}

public void setStreet_address(String street_address) {
    this.street_address = street_address;
}

public String getPostal_code() {
    return postal_code;
}

public void setPostal_code(String postal_code) {
    this.postal_code = postal_code;
}

public String getCity() {
    return city;
}

public void setCity(String city) {
    this.city = city;
}

public String getState_province() {
    return state_province;
}

public void setState_province(String state_province) {
    this.state_province = state_province;
}

public String getCountry_id() {
    return country_id;
}

public void setCountry_id(String country_id) {
    this.country_id = country_id;
}

@Override
public boolean equals(Object obj) {

    boolean isEqual = false;
    if (obj instanceof Cust_addressData) {
        Cust_addressData addressData = (Cust_addressData) obj;

        isEqual = addressData.getCity().equals(this.getCity())
                && addressData.getState_province().equals(this.getState_province())
                && addressData.getCountry_id().equals(this.getCountry_id())
                && addressData.getPostal_code().equals(this.getPostal_code())
                && addressData.getStreet_address().equals(this.getStreet_address())
                ;
    }
    return isEqual;
}

@Override
public int hashCode() {
    int hash = this.getCountry_id().hashCode();
    hash = hash * 17 + this.getPostal_code().hashCode();
    hash = hash * 31 + this.getStreet_address().hashCode();
    hash = hash * 13 + this.getState_province().hashCode();
    hash = hash * 14 + this.getCity().hashCode();
    return hash;
}

@Override
public String toString() {

    return "[ " + this.getClass() + " { city : " + city
            + ", street_address: " + street_address + ", postal_code: "
            + postal_code + ", state_province: " + state_province + ""
                    + ",country_id :"+country_id+"}]";
}

尝试为每个变量顶部的每一列添加正确的名称,不要公开。祝你好运