【问题标题】:Hibernate + PostgreSQL + Network Address Type (inet, cdir)Hibernate + PostgreSQL + 网络地址类型 (inet, cdir)
【发布时间】:2013-11-29 22:55:24
【问题描述】:

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

目前我想使用INET PostgreSQL type,但我无法使用 Hibernate 进行映射。

我收到了这个休眠错误:无法确定类型:inet,在表:DEVICE_IP_ADDRESS,列...

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

我的休眠映射文件:

<property name="ipAddress" type="inet">
     <column name="IP_ADDRESS" not-null="true" />
</property>

我问了谷歌,但我找不到任何可用的解决方案。 你能帮帮我吗?

谢谢!

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

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

【问题讨论】:

标签: java sql hibernate postgresql


【解决方案1】:

我最近在使用 Hibernate 3 和 Postgres 9 时遇到了类似的问题。由于没有为 postgres 中的 String Array 提供 Hibernate 到 Java String[] 的内置映射,我最终实现了一个自定义映射类。您可以尝试以下步骤。

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

    • 等于
    • nullSafeGet
    • nullSafeSet
    • 返回类 返回 InetAddress.class;
    • sql 类型 返回新的 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

希望这会有所帮助。

谢谢。

【讨论】:

    【解决方案2】:

    我只是解决了像你这样的问题。关于这件事的信息很少。正如@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
      }
    

    第二次创建为java处理的新对象,它必须有一个默认构造,一个用于处理来自DB的数据的构造并且是可序列化的。

    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
     }
    

    最后一步你必须创建一个自定义类型

    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);
    }
    
     }
    

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

    【讨论】:

    • 不适合我。抛出Caused by: org.postgresql.util.PSQLException: ERROR: invalid input syntax for type cidr: "com.xxx.yyy.model.PgCidrType。不过我正在使用 jpa...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 2018-02-13
    • 2018-08-16
    • 1970-01-01
    • 2014-10-08
    相关资源
    最近更新 更多