If you are storing your records in a database, you should really look into the capabilities available there to generate unique surrogate keys. In SQLServer this would be an IDENTITY field and in Oracle it would be a field that uses a SEQUENCE to generate a new value.
If there's a compelling reason why you can't use your database to generate a unique key, you should look at something like a Guid
- which has a mucher higher probability than date-time manipulation to generate a unique value. Guids can be trivially converted into strings, so your identifier would be a string in this case.
What you are doing with hashes is not a good idea - nothing gaurantees that hashes will be unique - and in many cases they do indeed collide. Guids - don't provide a 100% guarantee of uniqueness across machines but on a single machine they should always be unique. And even across machines, their chances of collision are extremely remote. Also, using machine time as a way to build up the underlying value is subject to race conditions (like those Eric describes).
Guids are 128-bit values, so you can't represent them as a simple int
or long
. It would require you to use string as your IDs, which may or may not be possible in your case, depending on other considerations (like whether or not you control the data model). If can use them, using a Guid is really easy:
string customerId = Guid.NewGuid().ToString(); // fetch new guid and save as string
string orderNumber = Guid.NewGuid().ToString(); // same story here...
If you really must use a numeric identifier, and you are willing to abandon easily scaling your application across multiple servers, you could use an auto-incrementing global number to supply a unique key. You would have to seed this number with the next available value (max+1) from your database when the application starts up. You would also have to then protect this value from concurrent use from multiple threads. I would wrap this responsibility in a class:
class static UniqueIDGenerator
{
// reads Max+1 from DB on startup
private static long m_NextID = InitializeFromDatabase();
public static long GetNextID() { return Interlocked.Increment( ref m_NextID ); }
}
EDIT: In this day and age, compelling reasons for generating unique IDs in your application layer rather than at the database are very uncommon. You should really use the capabilities that the database provides.