Hibernate + PostgreSQL +网络地址类型(inet,cdir)

zap*_*pee 8 java sql postgresql hibernate

我已经用Hibernate 4.2.7和PostgreSQL 9.3.1开始了我的示例项目,一切进展顺利.

目前我想使用INET PostgreSQL类型,但我无法用Hibernate映射它.

我得到了这个hibernate错误:无法确定类型:inet,在表:DEVICE_IP_ADDRESS,对于列...

我使用org.hibernate.dialect.PostgreSQLDialect和hbm.xml配置文件.

我的hibernate映射文件:

<property name="ipAddress" type="inet">
     <column name="IP_ADDRESS" not-null="true" />
</property>
Run Code Online (Sandbox Code Playgroud)

我问谷歌,但我找不到任何有用的解决方案.你可以帮帮我吗?

谢谢!

编辑:如果我想使用'额外'postgresql类型和PostGIS类型,我认为我需要使用什么样的ORM实现?

或者我需要使用简单的JDBC?

Raf*_*res 6

我只是解决了像你这样的问题.关于此事的信息很少.正如@ ms03所说...更好的方法是创建一个新类型和一个实现此类型的类,并处理java对象以设置/获取数据库.

首先在您的实体上,您必须为您的实体声明类型.

@Entity
@Table(name="user_app")
@TypeDefs(value={@TypeDef(name="convertInet",typeClass=PgInetType.class),
         @TypeDef(name="convertMacaddr",typeClass=PgMacaddrType.class)})
public class User implements Serializable {

    //some parameters

  @Type(type="convertMacaddr")
  private PgMacaddr mac;

  @Type(type="convertInet")
  private PgInet ip;

     //getters and setters, equals, hashcode, toString
  }
Run Code Online (Sandbox Code Playgroud)

第二个创建为java处理的新对象,它必须有一个默认构造,一个从DB处理数据的构造和Seriarizable.

public class PgInet implements Serializable {

private static final long serialVersionUID = 1L;

private String address;

public PgInet(String address){
    this.address=address;
}

public PgInet(){
    this.address=null;
}

    //Getters,setters,hashcode, equal and toString
 }
Run Code Online (Sandbox Code Playgroud)

最后一步,您必须创建自定义类型

public class PgInetType implements UserType{

@Override
public int[] sqlTypes() {

            //Because inet,macaddr,cdir...and unkwon type for java, yo must
            // define Types.OTHER
    return new int[] { Types.OTHER };
}

@Override
public Class returnedClass() {

            //Object created to be handled for java
    return PgInet.class;
}

@Override
public boolean equals(Object x, Object y) throws HibernateException {
    return ObjectUtils.nullSafeEquals(x, y);
}

@Override
public int hashCode(Object x) throws HibernateException {
    if(x!=null)
        return x.hashCode();
    else
        return 0;
}

@Override
public Object nullSafeGet(ResultSet rs, String[] names,
        SessionImplementor session, Object owner)
        throws HibernateException, SQLException {

            //Translation from DB to Java
    PgInet address=null;

    String ip=rs.getString(names[0]);

    if(ip!=null){
        address=new PgInet(ip);
    }

    return address;
}

@Override
public void nullSafeSet(PreparedStatement st, Object value, int index,
        SessionImplementor session) throws HibernateException, SQLException {

    //Translation from java to DB

    if(value==null){
        st.setNull(index, Types.VARCHAR);
    }else{

                //As inet,macaddr,cdir...are new types object on Postgresql you must
                //create the specific postgresql object and to insert it

                //I created 2 new cast on postgresql: inet As varchar, varchar AS inet
                //but I think it's not neccesary because macaddr type works fine without
                //postgresl casting

        st.setObject(index, getInet(value, st.getConnection()));
    }

}

private Object getInet(Object value, Connection connection) {

           //Expected object on postgresql

       Object tempInet = null;
       ClassLoader connectionClassLoader = connection.getClass().getClassLoader();

       try {

           //Class which will create the postgresql

           Class aPGObjectClass =connectionClassLoader.loadClass("org.postgresql.util.PGobject");
           Constructor ct = aPGObjectClass.getConstructor(null);
           try {
            tempInet = ct.newInstance(null);
        } catch (InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }

           Method setTypeMethod = aPGObjectClass.getMethod("setType", new Class[]{String.class});
           try {

               //Setting postgresql type, inet in this case

            setTypeMethod.invoke(tempInet, new Object[]{"inet"});
        } catch (IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

           Method setValueMethod = aPGObjectClass.getMethod("setValue", new Class[]{String.class});
           try {
            setValueMethod.invoke(tempInet, new Object[]{value.toString()});
        } catch (IllegalAccessException | IllegalArgumentException
                | InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

       } catch (ClassNotFoundException e) {

       } catch (NoSuchMethodException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SecurityException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

       return tempInet;
   }

@Override
public Object deepCopy(Object value) throws HibernateException {
    if(value==null)
        return null;
    else{
        PgInet PgInetNew=new PgInet();
        PgInet PgInetOriginal=(PgInet)value;

        PgInetNew.setAddress(PgInetOriginal.getAddress());

        return PgInetNew;
    }
}

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

@Override
public Serializable disassemble(Object value) throws HibernateException {
     Object  deepCopy=deepCopy(value);

      if(!(deepCopy instanceof Serializable))
       return (Serializable)deepCopy;

      return null;
}

@Override
public Object assemble(Serializable cached, Object owner)
        throws HibernateException {
    return deepCopy(cached);
}

@Override
public Object replace(Object original, Object target, Object owner)
        throws HibernateException {
    return deepCopy(original);
}

 }
Run Code Online (Sandbox Code Playgroud)

当我插入或从DB获取一行时,这种方式对我来说很好.


小智 3

我最近在 Hibernate 3 和 Postgres 9 中遇到了类似的问题。由于 hibernate 没有为 postgres 中的字符串数组到 Java String[] 提供内置映射,所以我最终实现了一个自定义映射类。您可以尝试按照以下步骤操作。

  1. 创建实现“org.hibernate.usertype.UserType”的自定义类“PgInet”(此 UserType 类是根据我的 hibernate 3 知识。不确定 Hibernate 4 中是否已更改)。
  2. 以下方法的实现至关重要。

    • 等于
    • 空安全获取
    • 空安全集
    • returnedClass 返回 InetAddress.class;
    • sqlTypes 返回新的 int[] {java.sql.Types.}

完成上述操作后,我们只需将 HBM​​.xml 中的属性类型设置为该类,即 PgInet。

对于自定义类实现,请尝试引用现有类型实现类。您应该能够找到类文件。使用下面的链接作为参考。

http://grepcode.com/file/repo1.maven.org/maven2/hibernate/hibernate/2.1.8/net/sf/hibernate/type/ArrayType.java

希望这可以帮助。

谢谢。