Pregunta

¿Cómo se deben implementar los iguales de clase y el código hash en Hibernate? ¿Cuáles son las trampas comunes? ¿La implementación predeterminada es lo suficientemente buena para la mayoría de los casos? ¿Tiene sentido usar claves de negocio?

Me parece que es bastante difícil hacer que funcione correctamente en cada situación, cuando se tiene en cuenta la recuperación perezosa, la generación de id, el proxy, etc.

¿Fue útil?

Solución

Hibernate tiene una descripción larga y agradable de cuándo / cómo anular equals () / hashCode () en documentación

Lo esencial es que solo debe preocuparse si su entidad formará parte de un Set o si va a separar / adjuntar sus instancias. Este último no es tan común. El primero generalmente se maneja mejor a través de:

  1. Basar equals () / hashCode () en una clave comercial, p. ej. una combinación única de atributos que no cambiará durante la vida útil del objeto (o, al menos, la sesión).
  2. Si lo anterior es imposible, la base es igual a () / hashCode () en la clave primaria SI está establecida y la identidad del objeto / System.identityHashCode () de lo contrario. La parte importante aquí es que necesita volver a cargar su Conjunto después de que se le haya agregado y persista una nueva entidad; de lo contrario, puede terminar con un comportamiento extraño (que en última instancia dará lugar a errores y / o corrupción de datos) porque su entidad puede asignarse a un depósito que no coincida con su hashCode () actual.

Otros consejos

No creo que la respuesta aceptada sea precisa.

Para responder la pregunta original:

  

¿La implementación predeterminada es lo suficientemente buena para la mayoría de los casos?

La respuesta es sí, en la mayoría de los casos lo es.

Solo necesita anular equals () y hashcode () si la entidad se utilizará en un Set (que es muy común ) Y la entidad se separará de, y posteriormente se volverá a unir a, las sesiones de hibernación (que es un uso poco común de hibernación).

La respuesta aceptada indica que los métodos deben ser anulados si la condición es verdadera.

Cuando una entidad se carga mediante carga diferida, no es una instancia del tipo base, sino que es un subtipo generado dinámicamente generado por javassist, por lo que fallará una comprobación del mismo tipo de clase, así que no use:

if (getClass() != that.getClass()) return false;

en su lugar usa:

if (!(otherObject instanceof Unit)) return false;

que también es una buena práctica, como se explica en Implementando iguales en las prácticas de Java .

por la misma razón, el acceso directo a los campos puede no funcionar y devolver nulo, en lugar del valor subyacente, así que no use la comparación en las propiedades, sino que use los captadores, ya que podrían disparar para cargar los valores subyacentes.

La mejor implementación de equals / hashCode es cuando utiliza una clave comercial única .

La clave comercial debe ser coherente en todos los estado de la entidad transiciones (transitorias, adjuntas, separadas, eliminadas), es por eso que no puede confiar en la id para la igualdad.

Otra opción es cambiar a identificadores UUID , asignados por la aplicación lógica. De esta manera, puede usar el UUID para equals / hashCode porque la identificación se asigna antes de que la entidad se vacíe.

Incluso puede usar el identificador de entidad para igual a y hashCode , pero eso requiere que siempre devuelva el mismo valor hashCode para que pueda asegúrese de que el valor hashCode de la entidad sea coherente en todas las transiciones de estado de la entidad. Consulte esta publicación para obtener más información sobre este tema .

Sí, es difícil. En mi proyecto, equals y hashCode dependen de la identificación del objeto. El problema de esta solución es que ninguno de ellos funciona si el objeto aún no se ha conservado, ya que la base de datos genera la identificación. En mi caso, eso es tolerable ya que en casi todos los casos los objetos persisten de inmediato. Aparte de eso, funciona muy bien y es fácil de implementar.

Si sucedió anular igual a , asegúrese de cumplir con sus contratos: -

  • SIMETRÍA
  • REFLECTIVO
  • TRANSITIVO
  • CONSISTENTE
  • NO NULL

Y anule hashCode , ya que su contrato se basa en la implementación de igual a .

Joshua Bloch (diseñador del marco de la Colección) instó firmemente a que se sigan estas reglas.

  • elemento 9: anular siempre el hashCode cuando anula igual a

Hay un efecto no deseado grave cuando no sigue estos contratos. Por ejemplo, List.contains (Object o) podría devolver un valor boolean incorrecto ya que el contrato general no se cumplió.

En la documentación de Hibernate 5.2 dice que es posible que no desee implementar hashCode y es igual, según su situación.

https: // docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode

Generalmente, dos objetos cargados desde la misma sesión serán iguales si son iguales en la base de datos (sin implementar hashCode e igual).

Se complica si estás usando dos o más sesiones. En este caso, la igualdad de dos objetos depende de la implementación de su método igual.

Además, te meterás en problemas si tu método igual está comparando ID que solo se generan mientras persisten un objeto por primera vez. Es posible que todavía no estén allí cuando se llama a igual.

Aquí hay un artículo muy agradable: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html

Citando una línea importante del artículo:

  

Recomendamos implementar equals () y hashCode () usando la tecla Business   igualdad. La igualdad empresarial clave significa que el método equals ()   compara solo las propiedades que forman la clave comercial, una clave que   identificaría nuestra instancia en el mundo real (un candidato natural   clave):

En términos simples

public class Cat {

...
public boolean equals(Object other) {
    //Basic test / class cast
    return this.catId==other.catId;
}

public int hashCode() {
    int result;

    return 3*this.catId; //any primenumber 
}

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top