Isn't there a possible problem when using lazy loaded polymorphic classes when using "T original = obj as T"?
If the current instance is a DomesticCat and the passed instance is a Cat proxy that, in fact, represents a DomesticCat instance then the cast would fail and return null because the Cat proxy cannot be cast to DomesticCat, wouldn't it?
The only way I can see around this problem is to use NHibernateUtil.GetClass(entity) but then this means that often an object would need to be loaded to determine its type, which would harm performance. It would be accurate though...
Thinking further on this topic, another consideration is that this approach will still break if you have a transient entity that you persist then evict from the Session thereby making it disconnected then compare it with a loaded entity with the same Id.
The loaded entity and the disconnected entity will be seen as equal but will have different hashcodes.
The only solution I can see that would be truly reliable would be to allocate an unique identifier at object creation and to persist it with the object. This value would then be consistent from initial transient object instantiation and would remain the same for all loaded instances of the entity too. This unique identifier would not necessarily have to be the Id property of the entity and would not need to be publicly exposed (just in case you're working with a legacy DB where the Id has business value - yuck, I know).
I do not completely agree with you.
You wrote that the hash code of an object should never change, but think about an Int32 object, when you change its value its hash code changes.
Also,if you will cache the hash code of transient object, then persist it and load it in another session, the hash code of the "used to be transient" object and the "loaded object" should be equal, but they will not be.
What do you think about that?
I agree with s.rottem 2nd point - if you create a new object, save it, disconnect it, and then check for equality with the same object after it was loaded from the db, you should get equality.
I think it is much easier to assign a "business key" to every persistent class - it will not be a key in any database sense, and the class should still have some kind of generated id column with no business logic, but a collection of (as few as possible) properties should define equality between two objects of the same class, and be used to calculate hashcode.
<p><p><p><p><p><p><p>I don't recommend writing Equals dependent to the id provided by the database. The business identity starts when the object is created and should not change when storing it (because storing does not change the object). It could be based on unique properties. We are using guids that are initialized in the constructor.</p></p></p></p></p></p></p>
<p><p><p><p><p><p><p>You could have bugs that only appear when the object is stored at a certain point (before or after a comparison). I wouldn't like to search such a bug.</p></p></p></p></p></p></p>
<p><p><p><p><p><p><p>I don't recommend to write such a == and != operator for regular entities. If you call those operators you normally expect a reference comparison. You don't want to look into the code of the entity to see if it has been overridden and does something sophisticated (which you need to know when you call it). So this kind of operator implementation is just making things more confusing. I would only do this for value types.</p></p></p></p></p></p></p>
<p><p><p><p><p><p><p>Have you ever had the same object in more than one instance? One from the database and one from the client? You need to find out that the object is identical (Equals), but not the same (==).</p></p></p></p></p></p></p>