nhibernate: ¿cuáles son las mejores prácticas para implementar la igualdad?
equality (1)
Creo que las entidades deberían implementar igualdad por comparación de clave primaria como predeterminada, pero la documentación de nhibernate recomienda usar identidad comercial:
La forma más obvia es implementar Equals () / GetHashCode () comparando el valor del identificador de ambos objetos. Si el valor es el mismo, ambos deben ser la misma fila de la base de datos, por lo tanto, son iguales (si ambos se agregan a un ISet, solo tendremos un elemento en el ISet). Desafortunadamente, no podemos usar ese enfoque. ¡NHibernate solo asignará valores de identificador a los objetos que son persistentes, una instancia recién creada no tendrá ningún valor de identificador! Recomendamos implementar Equals () y GetHashCode () usando Business Key Equity.
La igualdad de clave empresarial significa que el método Equals () compara solo las propiedades que forman la clave de negocio, una clave que identificaría nuestra instancia en el mundo real (una clave candidata natural)
Y el ejemplo (también del doc):
public override bool Equals(object other)
{
if (this == other) return true;
Cat cat = other as Cat;
if (cat == null) return false; // null or not a cat
if (Name != cat.Name) return false;
if (!Birthday.Equals(cat.Birthday)) return false;
return true;
}
Esto me dio vueltas porque la noción de identidad comercial (según el ejemplo) es igual a la comparación por sintaxis, que es básicamente el tipo de semántica que asocio con ValueObjects. El motivo por el que no se utilizan las claves primarias de la base de datos como valores de comparación es porque cambiará el código hash del objeto si la clave primaria no se genera en el lado del cliente (por ejemplo, incremental) y utiliza algún tipo de colección hashtable (como ISet) para almacenar tus entidades
¿Cómo puedo crear una buena implementación de igualdad que no rompa las reglas generales de igualdad / código hash ( http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx ) y se ajuste a las reglas de nhibernate también?
Este es un problema conocido con ORM. Aquí describo las soluciones que conozco y le doy algunos consejos.
1 clave sustituta / primaria: autogenerada
Como mencionaste, si el objeto no se ha guardado, esto no funciona.
2 clave sustituta / primaria: valor asignado
Puede decidir asignar el valor de la PK en el código, de esta manera el objeto siempre tiene una ID y se puede usar para comparar. Consulte No permita que hibernate le robe su identidad .
3 Clave natural
Si el objeto tiene otra clave natural, que no sea la clave principal, puede usar esta. Este sería el caso de una entidad cliente, que tiene una clave primaria numérica y un número de cliente de cadena. El número de cliente identifica al cliente en el mundo real y es una clave natural que no cambiará.
4 valores de objeto
Usar los valores del objeto para la igualdad es posible. Pero tiene otras deficiencias que ha mencionado. Esto puede ser problemático si los valores cambian y el objeto está en una colección . Por ejemplo, si tiene un Set
con dos objetos que eran diferentes al principio, pero luego cambia los valores mientras son referencia en el conjunto para que se vuelvan iguales. Entonces rompes el contrato del Set
. Ver Hibernate equals y hashcode .
5 Mixed: value + autogenerate primary / sustitutos claves
Si los objetos para comparar ya tienen una ID, úsala. De lo contrario, use los valores del objeto para la comparación.
Todos tienen algunos pros y contras. En mi humilde opinión, el mejor es 3, si es posible con su modelo de dominio. De lo contrario, he usado 5 y funcionó, aunque todavía hay alguna trampa al usar colecciones. Nunca usé 2, pero eso también suena como una solución sensata, si encuentras una forma de generar PK en el código. Tal vez otras personas tienen consejos para este.