NHibernate: Implementing Equals and GetHashCode

Conflicting advice abounds regarding the correct way to implement Equals and GetHashCode for NHibernate entities.

In general, any Equals implementation is required to be:

  • Transitive
  • Reflexive
  • Symmetric

A GetHashCode implementation must have the property that it returns the same value for any two objects for which Equals returns true (it may or may not return the same value for other object pairs).

One approach to determining equality is to compare each and every field between both entities. This approach doesn’t perform particularly well of course and, depending on the implementation, can be difficult to maintain.

I decided to base my Equals/GetHashCode implementation on object identity. All my entity objects are identified by a surrogate GUID that’s lazily initialized on first use. This allows me to implement the functionality in a base entity class and reuse it easily across all entities in the system:

public abstract class NHBEntity
{
    private Guid id;

    public virtual Guid Id
    {
        get
        {
            return (id == Guid.Empty) ? this.id = Guid.NewGuid() : this.id;
        }
        set
        {
            this.id = value;
        }
    }

    public override bool Equals(object obj)
    {
        if (obj == this) return true;

        var rhs = obj as NHBEntity;
        if (rhs == null) return false;

        return (this.Id.Equals(rhs.Id));
    }

    public override int GetHashCode()
    {
        return this.Id.GetHashCode();
    }
}

Being relatively new to NHibernate, I’m half anticipating having to make adjustments but so far this has worked well and, just as importantly, hasn’t been cumbersome to implement.

Comments off

Universally Unique Identifiers (UUIDs) as Surrogate Keys

Universally Unique Identifiers (UUIDs) make good surrogate keys for a number of reasons:

  • They are, by definition, globally unique, leading to practical benefits such as:
    • Given a UUID, it’s possible to identify the relation/tuple (and even potentially the database/environment) for which it is a key. This property can prove useful in the field when troubleshooting.
    • UUIDs will not clash across your environments (unless you want them to).
  • They are decentralised. By that I mean that any system is capable of generating a valid UUID. They can, for example, be generated by the middle-tier.
  • They are (somewhat) obscure – depending on the version of the algorithm used (usually version 4).
  • UUIDs can be generated offline.

 

UNIQUEIDENTIFIER is the SQL Server type for UUIDs. With SQL Server, there are some practical considerations that you need to weigh up for your scenario:

  • UNIQUEIDENTIFIERs require 16 bytes for storage (compared to 4 bytes for an INTEGER).
  • INSERTs will be randomly distributed if the UUID is generated via NEWID(). See NEWSEQUENTIALID() for an alternative.
  • JOINs and other operators involving UNIQUEIDENTIFIERs will likely perform worse compared to those involving INTEGERs.

 

Sometimes, the logical advantages of using UUIDs as generated keys in your system can outweigh these practical considerations.

Comments off

27” Apple iMac, Windows 7 installation and a blank screen

I recently picked up one of the new 27” iMacs with ATI Radeon 4850 graphics and so far I’m impressed. It’s a smart piece of hardware.

Out of necessity I need be able to boot into Windows 7 so I decided to install it (64-bit build) via Boot Camp. The first phase of setup proceeded without incident but at the point where Windows Setup loads the display driver, the screen went blank. It seems the ATI driver on the Win 7 RTM DVD doesn’t play nice with the ATI Radeon 4850 video in this particular iMac…

Fortunately, Setup doesn’t prompt for user input before rebooting …

To continue with Setup (or at least to be able to see anything on the screen) you need to intervene at this point and disable the ATI driver, here’s one way:

  • When prompted, hit any key to boot Windows Setup from the CD.
  • Select a Language, etc. and then click “Repair your computer”.
  • Select the Win 7 OS that you’re in the process of installing and click Next.
  • Start a Command Prompt and run regedit.
  • Highlight HKEY_LOCAL_MACHINE and then select File –> Load Hive…
  • Load the System hive from C:\Windows\System32\config\SYSTEM under say, “SystemHive”.
  • Locate the ATI driver (atikmdag) under SystemHive\ControlSetnnn\services and set Start to 4 (disabled). Here, nnn corresponds to the value at SystemHive\Select\Current.
  • Unload the hive, close regedit and reboot.

You should now be able to continue successfully with the remainder of Setup.

Once booted into Win 7, Windows Update will download the latest ATI driver which appears to work well and supports the native resolution of 2560 x 1440.

Now you can proceed as normal and install Boot Camp. Once done, you should have a fully functioning dual-boot 27” iMac!

Comments (3)

SQL Server “GO n” Batch Separator Tip

Did you know you can specify an integer following GO and the client tools will submit the batch the specified number of times? For example:

PRINT ‘GO’
GO 3

returns:

Beginning execution loop
GO
GO
GO
Batch execution completed 3 times.

Useful for, among other things, quickly generating test data.

Comments off

Internet Explorer 8 Frame/Session Merging

By default IE8 merges sessions across all open browser windows. This behaviour prevents you from, for example, having two IE windows open simultaneously that are each logged into different Windows Live accounts.

If you want to start IE reverted back to the IE7 and earlier behaviour of not  merging sessions across browser windows, use the –noframemerging option:

Start –> Run: iexplore –noframemerging

Comments off

« Previous Page« Previous entries « Previous Page · Next Page » Next entries »Next Page »