java - entitymanagerfactory - Corregir la anotación JPA para el tipo de texto de PostgreSQL sin anotaciones de Hibernate
java jpa example (3)
Como el tipo de text
no forma parte del estándar SQL, no creo que haya una forma oficial de JPA.
Sin embargo, el tipo de text
es bastante similar a varchar
, pero sin el límite de longitud. Puede indicar la implementación de JPA con la propiedad de length
de @Column
:
@Column(length=10485760)
private String description;
Actualización: 10 MiB parece ser la longitud máxima para varchar
en postgresql. El text
es casi ilimitado, según la documentation :
En cualquier caso, la cadena de caracteres más larga posible que se puede almacenar es de aproximadamente 1 GB.
Estoy desarrollando una aplicación usando:
- Java 1.7
- JPA (incluido en javaee-api 7.0)
- Hibernate 4.3.8.Final
- PostgreSQL-JDBC 9.4-1200-jdbc41
- PostgreSQL 9.3.6
Y me gustaría utilizar el tipo de datos de texto PostgreSQL para algunos atributos de cadena. Por lo que sé, en JPA esta debería ser la anotación correcta, para usar texto en PostgreSQL:
@Entity
public class Product{
...
@Lob
private String description;
....
}
Cuando anoto mi entidad de esta manera, me encuentro con errores que se ven así: http://www.shredzone.de/cilla/page/299/string-lobs-on-postgresql-with-hibernate-36.html
En resumen: parece que hibernate y jdbc no van de la mano para clob / text-types.
La solución descrita está funcionando:
@Entity
public class Product{
...
@Lob
@Type(type = "org.hibernate.type.TextType")
private String description;
...
}
Pero esto tiene un inconveniente importante: el código fuente necesita hibernación en tiempo de compilación, lo que debería ser innecesario (esa es una de las razones para usar JPA en primer lugar).
Otra forma es usar la anotación de columna como esta:
@Entity
public class Product{
...
@Column(columnDefinition = "text")
private String description;
...
}
Lo cual funciona muy bien, PERO: ahora estoy atascado con bases de datos que tienen un tipo de texto (y también se llama texto;)) y si se usará otra base de datos en el futuro, las anotaciones se pueden pasar por alto fácilmente. Por lo tanto, el posible error puede ser difícil de encontrar, porque el tipo de datos se define en una Cadena y, por lo tanto, no se puede encontrar antes del tiempo de ejecución.
¿Hay una solución, que es tan fácil, simplemente no lo veo? Estoy muy seguro de que no soy el único que usa JPA en combinación con Hibernate y PostgreSQL. Así que estoy un poco confundido de que no puedo encontrar más preguntas como esta.
Solo para completar la pregunta, persistence.xml se ve así:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="entityManager">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.app.model.Product</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost:5432/awesomedb" />
<property name="javax.persistence.jdbc.user" value="usr" />
<property name="javax.persistence.jdbc.password" value="pwd" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.jdbc.use_streams_for_binary" value="false" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
ACTUALIZAR:
Este problema es más o menos equivalente a esta pregunta, la respuesta elegida es la segunda forma de hacerlo descrita en esta pregunta, que no me gusta debido a la dependencia del tiempo de ejecución de hibernación: almacenar cadenas de longitud arbitraria en Postgresql
Esto parece estar relacionado con: https://hibernate.atlassian.net/browse/JPA-48
Me gustaría ir con private String description;
simple private String description;
. El tipo de columna es solo un problema si está generando la base de datos desde su código, ya que se generará como varchar
lugar de text
.
Es genial codificar de manera independiente de la base de datos, y sin ningún proveedor específico de JPA, pero hay casos donde esto simplemente no es posible. Si la realidad es que tendrá que admitir múltiples tipos de bases de datos con todos sus detalles, entonces tiene que dar cuenta de esos detalles en alguna parte. Una opción es usar columnDefinition
para definir el tipo de columna. Otra es dejar el código tal como está, y simplemente cambiar el tipo de columna en la base de datos. Yo prefiero el segundo.
Si desea utilizar JPA simple, puede remapear el tipo CLOB utilizado en el dialecto de esta manera:
public class PGSQLMapDialect extends PostgreSQL9Dialect {
@Override
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
if (Types.CLOB == sqlTypeDescriptor.getSqlType()) {
return LongVarcharTypeDescriptor.INSTANCE;
}
return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
}
}
Por lo tanto, no usará la asignación CLOB del controlador JDBC, que usa un OID para la columna y almacena / carga el texto mediante el manejo de objetos grandes. Esto solo daría como resultado llamadas setString y getString en la columna de texto createt en el Driver JDBC de Postgres a través de la clase VarcharTypeDescriptor.