2009-07-17 16 views
15

Hay mucho que se puede encontrar sobre este google un poco, pero no he encontrado una solución viable para este problema.Cargando una clob holgazaneamente en hibernación

Básicamente lo que tengo es un gran CLOB en una clase en particular que quiero haber cargado a pedido. La forma ingenua de hacer esto sería:

class MyType { 

    // ... 

    @Basic(fetch=FetchType.LAZY) 
    @Lob 
    public String getBlob() { 
    return blob; 
    } 
} 

eso no funciona, sin embargo, al parecer debido al hecho de que estoy usando controladores de Oracle, es decir, objetos Lob no son tratados como manijas simples pero siempre están cargados. O eso me han hecho creer por mis incursiones. Hay una solución que usa instrumentación especial para la carga de propiedades perezosas, pero como los documentos de Hibernate parecen sugerir que están menos que interesados ​​en hacer que funcione correctamente, así que prefiero no seguir esa ruta. Especialmente con tener que ejecutar un pase de compilación extra y todo.

Así que la siguiente solución que tenía previsto era separar este objeto a otro tipo y definir una asociación. Lamentablemente, aunque los documentos proporcionan información contradictoria, es evidente para mí que la carga diferida no funciona en las asociaciones de OneToOne con la clave primaria compartida. Establecí un lado de la asociación como ManyToOne, pero no estoy muy seguro de cómo hacerlo cuando hay una clave primaria compartida.

¿Alguien puede sugerir la mejor manera de hacerlo?

+0

¿Podría aclarar por qué no funciona con Oracle? – skaffman

+0

He desarrollado un poco ese aspecto, no estoy del todo seguro de cuál es el problema exacto (un poco vago en los detalles). Si el problema es con el mapeo, ¿podría dar uno que debería cargar perezoso el clob correctamente? – wds

+0

Si lo intentó con Oracle y falló, ¿cómo falló? – skaffman

Respuesta

5

Según this, solo PostgreSQL implementa Blob como realmente flojo. Entonces, la mejor solución es mover el blob a otra mesa. ¿Tienes que usar una clave primaria compartida? ¿Por qué no haces algo como esto:

public class MyBlobWrapper { 
    @Id 
    public Long getId() { 
     return id; 
    } 
    @Lob 
    public String getBlob() { 
     return blob; 
    } 
    @OneToOne(fetch=FetchType.LAZY,optional=false) 
    public MyClass getParent() { 
     return parent; 
    } 
} 
+0

El blob es solo un campo en la misma tabla, así que sí, tiene que usar una clave primaria compartida. Su enfoque funciona siempre que opcional = "falso" se establezca en el lado propietario. Supongo que se romperá horriblemente cuando el objeto sea nulo. – wds

+0

D'oh. Por supuesto, nunca será nulo ya que la clave principal existe. Solo será el campo de clob nulo. Un poco de un pensador allí, gracias. :-) – wds

+0

Este es el mapeo necesario en el lado padre por cierto (MyType). es posible que desee incluirlo en su respuesta: @OneToOne (fetch = FetchType.LAZY, optional = false) – wds

4

En vez de hacer equilibristics con anotaciones de hibernación, uno puede simplemente tratar de convertir el campo de String en Clob (o Blob):

@Lob 
@Basic(fetch=FetchType.LAZY) 
@Column(name = "FIELD_COLUMN") 
public Clob getFieldClob() { 
    return fieldClob; 
} 

public void setFieldClob(Clob fieldClob) { 
    this.fieldClob = fieldClob; 
} 

@Transient 
public String getField() 
{ 
    if (this.getFieldClob()==null){ 
    return null; 
    } 
    try { 
    return MyOwnUtils.readStream(this.getFieldClob().getCharacterStream()); 
    } catch (Exception e) { 
    e.printStackTrace(); 
    } 

    return null; 
} 

public void setField(String field) 
{ 
    this.fieldClob = Hibernate.createClob(field); 
} 

Trabajó para el yo (el campo comenzó a cargarse perezosamente, en Oracle).

+0

¿Cómo funciona? esto causa que el campo se cargue flojamente? Por lo que puedo decir, ¿esto solo agrega conveniencia getter/setter para acceder al lob como una cadena? –

+0

@BenGeorge Tenga en cuenta que la anotación Lob se está poniendo en un captador de Clob en mi respuesta, a diferencia de un captador de cadenas en la pregunta. Y no uso el campo Clob directamente, sino solo a través de un getter transitorio. Advertencia: la versión de Hibernate en la que probé esto fue, si no recuerdo mal, 3.2. Para verificar que la carga era floja, utilicé Wireshark para inspeccionar el tráfico hacia y desde la base de datos. –

3

Ya que parecen estar utilizando Hibernate me pregunto si su problema está relacionado con la siguiente función de hibernación:

Using Lazy Properties Fetching

Hibernate3 apoya la recuperación perezosa de propiedades individuales. Esta técnica de optimización también se conoce como grupos de búsqueda. Tenga en cuenta que esto es principalmente una función de marketing; La optimización de las lecturas de filas es mucho más importante que la optimización de las lecturas de columna de . Sin embargo, solo cargar algunas propiedades de una clase podría ser útil en casos extremos. Para el ejemplo , cuando las tablas heredadas tienen cientos de columnas y el modelo de datos no se puede mejorar.

Lazy property loading requires buildtime bytecode instrumentation. Si sus clases persistentes no son mejoradas, Hibernate ignorará la configuración de propiedad de y volverá a la recuperación inmediata.

Ver Bytecode Instrumentation for Hibernate Using Maven.

0

Publicación anterior, pero solo una que me ayudó, gracias a la respuesta de @TadeuszKopec.

Parece que es difícil hacer una carga lenta de blob con JPA. Intenté la asociación @OneToOne, pero esto complica más que la ayuda. Me acabo de mudar los bytes a otra clase, sin asociación con MiClase (padre misma mesa, el mismo id.):

@Entity 
@Table(name="MyTable") 
public class MyBlobWrapper{ 

    @Id 
    @Column(name = "id") // id of MyTable, same as MyClass 
    private Long id; 

    @Lob 
    private byte[] bytes; 
} 

@Entity 
@Table(name="MyTable") 
public class MyClass{ 

    @Id 
    @Column(name = "id") 
    private Long id; 
    // other fields ..... 
} 

Sólo recuerde para limpiar los padres, antes de guardar la burbuja:

em.persist(parent); 
em.flush(); 
em.merge(new MyBlobWrapper(parent_id,new byte[1000])); 

Ahora puedo cargar el pdf solo:

String query1 = " select PDF from MyBlobWrapper PDF where PDF.id = :id"; 

Solo soy principiante con JPA, espero que ayude.