How can the following problem be dealt with?
We’re using lazy loaded NHibernate properties and whenever we’re calling Equals() or GetHashCode() any properties used, will be lazy-loaded, potentially causing a cascade of lazy-loading operations. Eager-loading could be used as an alternative, but I think only in specific cases and not as a general solution.
A typical scenario would look like this:
public class AbstractSaveableObject {
[Id(0, Name = "Id", UnsavedValue = null)]
[Generator(1, Class = "native")]
public virtual long? Id { get; set; }
}
[Class(NameType = typeof(ClassA))]
public class ClassA : AbstractSavableObject {
[Bag(0, Inverse = true, Cascade = "none")]
[Key(1, Column = "ClassA")]
[OneToMany(2, ClassType = typeof(ClassB))]
public virtual ICollection<ClassB> ClassBs { get; set; }
}
[Class(NameType = typeof(ClassB))]
public class ClassB : AbstractSavableObject {
[ManyToOne(Column = "ClassA")]
public virtual ClassA ClassA { get; set; }
[ManyToOne]
public virtual ClassC ClassC { get; set; }
[ManyToOne]
public virtual ClassD ClassD { get; set; }
public virtual bool Equals(ClassB other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Equals(other.ClassC, ClassC) && Equals(other.ClassD, ClassD);
}
}
Implementation of GetHashCode and Equals(object) have been omitted for brevity.
What strategies can be been used to tackle this issue?
Two entities are equal if they are of the same type and has the same primary key.
If you have integers for keys:
If you have GUIDs for keys:
If I have integers for keys I usually have something like this Equal-override in a base class for my entities:
Now if you entities that inherit from others using table per hierarchy you will face the problem that GetClassWithoutInitializingProxy will return the base class of the hierarchy if it’s a proxy and the more specific type if it’s a loaded entity. In one project I got around that by traversing the hierarchy and thus always comparing the base types – proxy or not.
In these days though I would always go for using GUIDs as keys and do as described here: http://nhibernate.info/doc/patternsandpractices/identity-field-equality-and-hash-code.html
Then there is no proxy type mismatch problem.