hibernate - entidades - Hibernación: cómo conservar un elemento nuevo en una colección sin cargar la colección completa
hibernate eclipse (3)
Cuando tiene una colección basada en la Lista o en el Conjunto y agrega un nuevo objeto a su colección, Hibernate siempre llegará a la base de datos porque compara uno por uno al usar la implementación de partes iguales antes de guardar o actualizar, cuando se usa un Conjunto, o al comparar una columna de índice cuando se utiliza una lista. Este comportamiento es necesario debido a la semántica Set and List. Debido a eso, el rendimiento de su aplicación puede disminuir significativamente si tiene un montón de registros.
Algunas soluciones para superar este problema.
1º Patrón de conversión mediante el uso de una colección de bolsas encapsulada más el conjunto o la lista que desee como propiedad
@Entity
public class One {
private Collection<Many> manyCollection = new ArrayList<Many>();
@Transient
public Set<Many> getManyCollectionAsSet() { return new HashSet<Many>(manyCollection); }
public void setManyCollectionAsSet(Set<Many> manySet) { manyCollection = new ArrayList<Many>(manySet); }
/**
* Keep in mind that, unlike Hibernate, JPA specification does not allow private visibility. You should use public or protected instead
*/
@OneToMany(cascade=ALL)
private Collection<Many> getManyCollection() { return manyCollection; }
private void setManyCollection(Collection<Many> manyCollection) { this.manyCollection = manyCollection; }
}
2º Usa ManyToOne en lugar de OneToMany
@Entity
public class One {
/**
* Neither cascade nor reference
*/
}
@Entity
public class Many {
private One one;
@ManyToOne(cascade=ALL)
public One getOne() { return one; }
public void setOne(One one) { this.one = one }
}
3º Almacenamiento en caché: cuando se aplica debido a que, según sus requisitos, su configuración puede aumentar o disminuir el rendimiento de su aplicación. Ver here
4 ° restricción de SQL: si desea una colección que se comporte como un conjunto, puede usar una restricción de SQL, que se puede aplicar a una columna o conjunto de columnas . Ver here
Tengo una colección en mi modelo que contiene un conjunto de "versiones anteriores" de mi objeto de dominio raíz. Las versiones anteriores son, por lo tanto, ''inmutables'' y nunca desearemos actualizarlas, y solo queremos agregar versiones anteriores a medida que surjan. Además, el objeto de dominio "versionado" es bastante complejo y hace que el acceso a la base de datos sea pesado para recuperar.
Cuando tenga una nueva versión de uno de estos objetos, quiero guardarlo con los otros sin cargar todo el conjunto. El FAQ avanzado tiene algunos consejos sobre esto:
¿Por qué Hibernate siempre inicializa una colección cuando solo quiero agregar o eliminar un elemento?
Desafortunadamente, la API de colecciones define los valores de retorno de los métodos que solo se pueden calcular al golpear la base de datos. Hay tres excepciones a esto: Hibernate puede agregarse a un
<bag>
,<idbag>
o<list>
declarado coninverse="true"
sin inicializar la colección; el valor de retorno siempre debe ser verdadero.Si desea evitar el tráfico de base de datos adicional (es decir, en el código de rendimiento crítico), refactorice su modelo para que use solo asociaciones de muchos a uno. Esto es casi siempre posible. Luego use las consultas en lugar del acceso a la colección.
Soy nuevo en todo esto y no estoy 100% seguro de cómo refactorizar su modelo para usar solo asociaciones de muchos a uno. ¿Alguien puede darme un ejemplo de señalarme un tutorial para que pueda aprender cómo esto resolverá mi problema?
La forma en que normalmente hago esto es definir la colección como "inversa".
Eso significa aproximadamente: la definición primaria de la asociación 1-N se realiza en el extremo "N". Si desea agregar algo a la colección, altera el objeto asociado de los datos detallados.
Un pequeño ejemplo de XML:
<class name="common.hibernate.Person" table="person">
<id name="id" type="long" column="PERSON_ID">
<generator class="assigned"/>
</id>
<property name="name"/>
<bag name="addresses" inverse="true">
<key column="PERSON_ID"/>
<one-to-many class="common.hibernate.Address"/>
</bag>
</class>
<class name="common.hibernate.Address" table="ADDRESS">
<id name="id" column="ADDRESS_ID"/>
<property name="street"/>
<many-to-one name="person" column="PERSON_ID"/>
</class>
entonces la actualización se realiza exclusivamente en Dirección:
Address a = ...;
a.setPerson(me);
a.setStreet("abc");
Session s = ...;
s.save(a);
Hecho. Ni siquiera tocaste la colección. Considérelo como de solo lectura, lo que puede ser muy práctico para consultar con HQL e iterarlo y mostrarlo.
Si entiendo bien tu necesidad:
- tienes una colección de objetos inmutables en la memoria que se agrega solo
- ¿Cómo agregar un elemento a esa colección sin inicializar toda la colección (en la sesión actual)?
¿Consideraste mantener desconectada tu colección ?
- Cárgalo una vez cuando se inicie la aplicación.
- Agregar un elemento significaría dos operaciones, realizadas por un solo servicio en un solo lugar:
- guardar el elemento (operación rápida de la base de datos, no se hace una cascada al padre)
- agregue el elemento a la colección desconectada existente (sin operación de base de datos)