2011-07-19 13 views
10

Al usar @ElementCollection, cargar todo está cargando varias instancias de un objeto. Más específicamente, está cargando una instancia para cada elemento en collectionOfStrings.@ElementCollection Java Persistence (Hibernate) Causa la carga de instancias duplicadas

Por ejemplo, una base de datos con una sola instancia de MyClass con collectionOfStrings.size() == 4, la llamada para cargar todos los valores MyClass devolverá una lista de tamaño 4 (todo el mismo objeto) en lugar de sólo 1 objeto .

¿Existe una forma clara y sencilla de resolver esto o se espera el comportamiento?

// Parent class is a @MappedSuperclass which may or may not be relevant to the issue 
@Entity 
public class MyClass extends ParentClass { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @ElementCollection(fetch=FetchType.EAGER) 
    @IndexColumn(name="indexColumn") 
    private List<String> collectionOfStrings; 

    // other instance variables, constructors, getters, setters, toString, hashcode and equals 
} 

public class MyClassDAO_Hibernate extends GenericHibernateDAO<MyClass, Long> implements MyClassDAO { 

    @Override 
    public List<MyClass> loadAll() { 
     List<MyClass> entityList = null; 
     Session session = getSession(); 
     Transaction trans = session.beginTransaction(); 
     entityList = findByCriteria(session); 
     trans.commit(); 
     return entityList; 
    } 

} 

protected List<T> findByCriteria(Session session, Criterion... criterion) { 
    Criteria crit = session.createCriteria(getPersistentClass()); 
    for (Criterion c : criterion) { 
     crit.add(c); 
    } 
    return crit.list(); 
} 

MyClassDAO myClassDAO = new MyClassDAO_Hibernate(); // in reality, implementation type is determined with a Factory 
... 
List<MyClass> myClassInstances = myClassDAO.loadAll(); 

Gracias, HeavyE

Editar: se ha añadido la llamada findByCriteria.

+0

¿Cómo cargas entidades? – axtavt

+0

axtavt, agregué en mi método findByCriteria que no incluí originalmente. – HeavyE

Respuesta

8

no estoy seguro de si se trata de un error o un comportamiento legítimo, pero se puede fijar mediante la aplicación de transformador DISTINCT_ROOT_ENTITY resultado:

protected List<T> findByCriteria(Session session, Criterion... criterion) { 
    Criteria crit = session.createCriteria(getPersistentClass()); 
    for (Criterion c : criterion) { 
     crit.add(c); 
    } 
    crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 
    return crit.list(); 
} 
+0

Funcionó perfectamente - ¡Gracias! – HeavyE

2

Este es el comportamiento correcto de la Lista. La lista permite la duplicación de objetos y esta es la razón por la cual necesita una columna indexada.

Estos son el tipo de colección general que puede ser mapeado por Hibernate:

Conjunto es una colección en la que no hay ningún elemento se produce más de una vez. Este es el tipo de colección persistente más común, en mi experiencia.

Bolsa es un colleciton en el que los elementos pueden aparecer más de una vez: son muy ineficientes porque hibernación No se puede saber si los artículos que puso en él son los mismos que los que ya están en ella (suponiendo que son iguales), por lo tiene que eliminar toda la colección y volver a guardarla de la memoria.

La lista es una bolsa indexada. El índice permite que hibernate sepa si un objeto en memoria en particular es el mismo que un objeto igual en DB, por lo que no es necesario eliminar/volver a insertar.

El mapa es como una lista, excepto que el índice no tiene que ser un entero computable (generalmente secuencial), puede ser cualquier cosa, incluso otro objeto.

En su caso, le recomiendo que use Set.

+2

Desafortunadamente, usar un Set no funcionará para esta clase; se requiere una Lista ya que es una colección ordenada. Para aclarar, el problema no es que la Lista 'collectionOfStrings' contenga duplicados sino que la Lista 'myClassInstances' contenga duplicados. – HeavyE

2

Esto se observa sólo cuando la colección es recuperada tempranamente. Hibernate traduce este mapeo de anotación en una consulta de unión externa, lo que causa un número múltiple en la lista de elementos raíz para cada elemento linkedOfString vinculado.

Consulte el ticket HHH-6783 en el rastreador de problemas de ORM de Hibernate para este problema exacto. Y aparentemente no hay solución. :-(

Un enlace to the Hibernate FAQ que se dedica a problemas con combinación externa también se proporciona aquí.

estoy tratando con el mismo problema exacto. El uso de un @ElementCollection tiene sentido en mi caso, pero no en el costo de revisar todas mis implementaciones de capa de acceso a datos. ¿Qué debo hacer?

+0

Está marcado como un error en HHH-6783, pero me huele mucho a un error. Recurrí a LAZY con Hibernate.initialize() ya que en mi caso de uso solo se devuelven unos pocos objetos y las consultas de N + 1 son correctas. –

Cuestiones relacionadas