I have the following t-sql code which I have converted to c#.
DECLARE #guidRegular UNIQUEIDENTIFIER, #dtmNow DATETIME
SELECT #guidRegular = '{5bf8e554-8dbc-4008-9d48-5c6e0a4d28d7}'
SELECT #dtmNow = '2012-02-09 18:31:38'
print (CAST(CAST(#guidRegular AS BINARY(10)) + CAST(#dtmNow AS BINARY(6)) AS UNIQUEIDENTIFIER))
When I execute the .net version of the code (using same Guid and DateTime) I Get a different guid? It looks like it has something to do with the datetime element can anyone help ?
c# extension code:
using system.data.linq;
...
...
public static class GuidExtensions
{
public static Guid ToNewModifiedGuid(this Guid guid)
{
var dateTime = new DateTime(2012,02,09,18,31,38);
var guidBinary = new Binary(guid.ToByteArray().Take(10).ToArray());
var dateBinary = new Binary(BitConverter.GetBytes(dateTime.ToBinary()).ToArray().Take(6).ToArray());
var bytes = new byte[guidBinary.Length + dateBinary.Length];
Buffer.BlockCopy(guidBinary.ToArray(), 0, bytes, 0, guidBinary.ToArray().Length);
Buffer.BlockCopy(dateBinary.ToArray(), 0, bytes, guidBinary.ToArray().Length, dateBinary.ToArray().Length);
return new Guid(bytes);
}
}
I'm not surprised that SQL and .net would have different binary representations of a date/time. I would be surprised if they had.
Your c# code is asking the DateTime structure to serialize a value to a 64-bit ( 8 byte) byte array that can be used to recreate the same value. Then you're throwing away 2 bytes (the year? the millisecond? a checksum? who knows?)
Your sql code is asking the sql engine to take it's internal representation of a datetime - which is also 8 bytes - throw away two, and give the result.
So:
If you want identical values, you would need to stop relying on the internals of how a datetime is stored / serialized. Convert it to 6 bytes using a repeatable method you can write in both .net and tsql
Realize that you are removing the 6 bytes of a guid that represent the spatially unique portion and replacing them with the time. So you are creating a GUID that has the time encoded twice, and are greatly increasing the odds of duplicate GUIDs being created.
Of course, this ignores the more glaring issue of "why would anyone want to do that?" I'm going to assume that it's some really brilliant subsystem, instead of the more likely explanation that somebody is desperately trying to solve the wrong problem.
The original article has a flaw in the logic. The author describes both Natural and Surrogate keys but doesn't recognize that the RFC for UUIDs can be used to create a Natural key. Of course, doing so would require creating a custom function for generating a UUID based on some solution domain information, rather than relying on the default machine/time-based function for their generation.
Doing a single function to replace the generation of the keys makes a lot more sense than this, though.
Related
SCENARIO
I would like to learn, in C# or VB.NET, how to generate a Hardware Id. based on the same methodology Microsoft developers does for that.
First of all before continue I must advertise this question is a better specific different question derivated from this other question: Get Hardware IDs like Microsoft does
And the basic concerns for the creation of a Microsoft's HWID, which is based on the SMBIOS table, are described in the answers of that question linked above, and more deeply here: Specifying Hardware IDs for a Computer
And my reason for trying to reproduce their methodology is just to follow a professional standard guidelines about how to do things in the right way: Microsoft's way.
PROBLEM
Since getting the SMBIOS table from managed .NET seems a impossible/not implemented task, and also I can't find any demostrative usage example of the Win32 function: GetSystemFirmwareTable, and anyways the fields parsing of a SMBIOS table it seems a real nightmare that is too much work for one single dev. ...because I suspect a working parser algorithm would need to be maintained/updated from short time to time: SMBIOS version history
...Then I assumed all that, and I choose to use the WMI classes to reproduce with limitations (SMBIOS fields that WMI doesn't expose or always are null using WMI) all what I could reproduce from the original concepts of Microsoft's HWID implementation.
To try start reproducing what Microsoft does, I attempted to start generating the HWID that just takes one field: the SMBIOS manufacturer.
My problem is that I'm doing something wrong and I don't know exactly what it could be...
So, the problems I noticed with my code:
My resulting SHA-1 string differs from the GUID that is built with the SHA-1 that is generated using the ComputerHardwareIds.exe tool contained in the WDK/SDK: ComputerHardwareIds specifications
(the basics for those HWID creation are explained in the urls that I linked inside the 'SCENARIO' section of this question, I insist)
My resulting SHA-1 string is 40 char. length. The System.GUID structure doesns't expects a string of this length, neither accepts the raw Byte-Array data of my computed SHA-1.
#Richard Hughes he said here:
You then need to use a type 5 (SHA-1) UUID generation scheme with
70ffd812-4c7f-4c7d-0000-000000000000 as the namespace
...But I admit I don't understand what he means about using a namespace for a cypher?. I'm probably missing that detail when building my SHA-1 string. I tried to analyze the members of the SHA1CryptoServiceProvider class in search for some property where to specify a namespace... nothing found.
This is the code I'm using, where I hardcoded the manufacturer string retrieval just to simplify things:
C# sample:
string manufacturer = "American Megatrends Inc.";
byte[] charBuff = Encoding.Unicode.GetBytes(manufacturer); // UTF-16
byte[] hashBuff = null;
string hashStr = null;
using (SHA1CryptoServiceProvider cypher = new SHA1CryptoServiceProvider()) {
hashBuff = cypher.ComputeHash(charBuff);
hashStr = BitConverter.ToString(hashBuff).Replace("-", ""); // Same string conversion methodology employed in a MSDN article.
}
Debug.WriteLine("SHA-1=\"{0}\"", hashStr); // SHA-1="0E74E534EE9F1985AE173C640302F58121190593"
Guid guid = new Guid(hashBuff); // System.ArgumentException: 'Byte array for GUID must be exactly 16 bytes long.'
VB.NET sample:
Dim manufacturer As String = "American Megatrends Inc."
Dim charBuff As Byte() = Encoding.Unicode.GetBytes(manufacturer) ' UTF-16
Dim hashBuff As Byte()
Dim hashStr As String
Using cypher As New SHA1CryptoServiceProvider
hashBuff = cypher.ComputeHash(charBuff)
hashStr = BitConverter.ToString(hashBuff).Replace("-", "") ' Same string conversion methodology employed in a MSDN article.
End Using
Debug.WriteLine("SHA-1=""{0}""", hashStr) ' SHA-1="0E74E534EE9F1985AE173C640302F58121190593"
Dim guid As New Guid(hashBuff) ' System.ArgumentException: 'Byte array for GUID must be exactly 16 bytes long.'
The expected resulting GUID would be the same GUID that the ComputerHardwareIds.exe tool generates:
{035a20a6-fccf-5040-bc3e-b8b794c57f52} <- Manufacturer
QUESTION
Well, just... what I need and how can I fix my code to get the expected result?.
I'm developing a ticketing system for tracking bugs and software changes using ASP.NET MVC 4 and Entity Framework 5. I need a way to pick a unique number from a set of possible numbers. My thought is to create a set of possible numbers and mark numbers from this set as they are used and assigned to a support ticket.
I have this code for generating all possible ticket numbers to choose from, but I want to have leading zeroes so that all ticket numbers have the same length:
public static class GenerateNumber
{
private static IEnumerable<int> GenerateNumbers(int count)
{
return Enumerable.Range(0, count);
}
public static IEnumerable<string> GenerateTicketNumbers(int count)
{
return GenerateNumbers(count).Select(n => "TN" + n.ToString());
}
}
I want the output of
IEnumerable<string> ticketNumbers = GenerateNumber.GenerateTicketNumbers(Int32.MaxValue);
to be something like this:
TN0000000001
.
.
.
TN2147483647
Hopefully we won't need anything as large as Int32.MaxValue as that would mean we have way too many bugs haha. I just wanted to be safe than sorry on the limits of the available numbers. Perhaps we could use the methodology of reusing ticket numbers after they have been resolved. However, I don't know how I feel about reuse as it could lead to ambiguity for referring to documentation later on.
Considering the size of this set, is this the most efficient method to go about having unique ticket numbers?
Use an identity column in the database - this will autoincrement for you.
If you need a prefix as well, then store this as a separate varchar column and then for display purposes you can concatenate it (with your requisite leading zeros if that is absolutely really necessary). Trying to store an incrementing number in a varchar field is going to bite you in the ass one day.
As a side note, why the leading zeros? If I am fixing a ticket, I want to annotate my code with the ticket number. Leading zeros are just a pain - why not just have TN-123 and have the number get bigger as required?
Background (You can skip this section)
I have a large amount of data (about 3 mb) that needs to be kept up to date on several hundred machines. Some of the machines run C# and some run Java. The data could change at any time and needs to be propogated to the clients within minutes. The data is delivered in Json format from 4 load balanced servers. These 4 servers are running ASP.NET 4.0 with Mvc 3 and C# 4.0.
The code that runs on the 4 servers has a hashing algorithm which hashes the Json response and then converts the hash to a string. This hash is given to the client. Then, every few minutes, the clients ping the server with the hash and if the hash is out of date the new Json object is returned. If the hash is still current then a 304 with an emptry body is returned.
Occasionally the hashes generated by the 4 boxes are inconsistent across the boxes, which means that the clients are constantly downloading the data (each request could hit a different server).
Code Snipet
Here is the code that is used to generate the hash.
internal static HashAlgorithm Hasher { get; set; }
...
Hasher = new SHA1Managed();
...
Convert.ToBase64String(Hasher.ComputeHash(Encoding.ASCII.GetBytes(jsonString)));
To try and debug the problem I split it out like this:
Prehash = PreHashBuilder.ToString();
ASCIIBytes = Encoding.ASCII.GetBytes(Prehash);
HashedBytes = Hasher.ComputeHash(ASCIIBytes);
Hash = Convert.ToBase64String(HashedBytes);
I then added a route which spits out the above values and used Beyond Compare to compare the differences.
Byte arrays are converted to a string format for BeyondCompare use by using:
private static string GetString(byte[] bytes)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in bytes)
{
sb.Append(b);
}
return sb.ToString();
}
As you can see the byte array is displayed litterally as a sequence of bytes. It is not 'converted'.
The Problem
I discovered that the Prehash and ASCIIBytes values were the same, but the HashedBytes values were different - which meant that the Hash was also different.
I restarted the IIS WebSites on the 4 server boxes several times and, when they had different hashes, compared the values in BeyondCompare. In everycase it was the "HashedBytes" value that was different (the results of SHA1Managed.ComputeHash(...))
The Question
What am I doing wrong? The input to the ComputeHash function is identical. Is SHA1Managed machine dependent? That doesn't make since because half the time the 4 machines have the same hash.
I have searched StackOverFlow and Bing but have been unable to find anyone else with this problem. The closest thing I could find was people with problems with their encoding, but I think I have proven that the encoding is not an issue.
Output
I was hoping not to dump everything here because of how long it is, but here is a snipet of the dump I am comparing:
Hash:o1ZxBaVuU6OhE6De96wJXUvmz3M=
HashedBytes:163861135165110831631611916022224717299375230207115
ASCIIBytes:1151169710310146991111094779114100101114831011141181059910147115101114118105991014611511899591151051031101171129511510111411810599101114101102101114101110991011159598979910710111010011111410010111411510111411810599101951185095117114108611041161161125847471051159897991071011101004610910211598101115116971031014699111109477911410010111483101114118105991014711510111411810599101461151189947118505911510510311011711295115101114118105991011141011021011141011109910111595989799107101110100112971211091011101161151161111141011151011141....
Prehash:...
When I compare the two pages on the different servers the ASCII Bytes are identical but the HashedBytes are not. The dump method I use for the bytes does no conversions, it simply dumps each byte out in sequence. I could delimit the bytes with a '.' I suppose.
Follow Up
I have made the b.ToString(CultureInfo.InvariantCulture) change and have made the HashAlgorithm a local variable instead of a static property. I am waiting for the code to deploy to the servers.
I have been trying to duplicate the issue but have been unable to do so once I made the SHA1Managed property a local variable instead of global static.
The problem was with Multi-Threading. My code was thread safe except for the SHA1Managed class that I had marked static. I assumed that SHA1Managed.ComputeHash would be thread safe underneath but apparently it is not if marked internal static.
To repeat, SHA1Managed.ComputeHash is not thread safe if marked internal static.
MSDN states:
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
I don't know why internal static behaves differently than public static.
I would mark #pst as the answer and add a comment to clarify the problem, but #pst made a comment so I can't mark it as the answer.
Thanks for all your input.
Your GetString method could potentially produce different results on machines of different cultures, because StringBuilder.Append(byte) calls byte.ToString(CultureInfo.CurrentCulture). Try
private static string GetString(byte[] bytes)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in bytes)
{
sb.Append(b.ToString(CultureInfo.InvariantCulture));
}
return sb.ToString();
}
But using a method that doesn't use decimal string representations of the byte values would be better.
The problem is your code is likely messing with leading 0's, use the following as your array to string code to compare. it will produce reliable results and is specifically designed for turning byte arrays in to strings so they can be transmitted between machines.
using System.Runtime.Remoting.Metadata.W3cXsd2001;
public byte[] StringToBytes(string value)
{
SoapHexBinary soapHexBinary = SoapHexBinary.Parse(value);
return soapHexBinary.Value;
}
public string BytesToString(byte[] value)
{
SoapHexBinary soapHexBinary = new SoapHexBinary(value);
return soapHexBinary.ToString();
}
Also, I would recommend that you check that the JSON is not subtlety different, as that would create a totally diffrent hash. For example some cultures represent the number "One thousand six hundred point seven" as 1,600.7, 1 000.7, or even 1 600,7 (see this Wikipedia page).
I try to use long as unique id within our C# application (not global, and only for one session) for our events. Do you know if the following will generate an unique long id?
public long GenerateId()
{
byte[] buffer = Guid.NewGuid().ToByteArray();
return BitConverter.ToInt64(buffer, 0);
}
Why we not use GUID directly? We think 8 bytes long is good enough.
No, it won't. As highlighted many times on Raymond Chen's blog, the GUID is designed to be unique as a whole, if you cut out just a piece of it (e.g. taking only 64 bytes out of its 128) it will lose its (pseudo-)uniqueness guarantees.
Here it is:
A customer needed to generate an 8-byte unique value, and their initial idea was to generate a GUID and throw away the second half, keeping the first eight bytes. They wanted to know if this was a good idea.
No, it's not a good idea.
(...)
Once you see how it all works, it's clear that you can't just throw away part of the GUID since all the parts (well, except for the fixed parts) work together to establish the uniqueness. If you take any of the three parts away, the algorithm falls apart. In particular, keeping just the first eight bytes (64 bits) gives you the timestamp and four constant bits; in other words, all you have is a timestamp, not a GUID.
Since it's just a timestamp, you can have collisions. If two computers generate one of these "truncated GUIDs" at the same time, they will generate the same result. Or if the system clock goes backward in time due to a clock reset, you'll start regenerating GUIDs that you had generated the first time it was that time.
I try to use long as unique id within our C# application (not global, and only for one session.) for our events. do you know the following will generate an unique long id?
Why don't you just use a counter?
You cannot distill a 16-bit value down to an 8-bit value while still retaining the same degree of uniqueness. If uniqueness is critical, don't "roll your own" anything. Stick with GUIDs unless you really know what you're doing.
If a relatively naive implementation of uniqueness is sufficient then it's still better to generate your own IDs rather than derive them from GUIDs. The following code snippet is extracted from a "Locally Unique Identifier" class I find myself using fairly often. It makes it easy to define both the length and the range of characters output.
using System.Security.Cryptography;
using System.Text;
public class LUID
{
private static readonly RNGCryptoServiceProvider RandomGenerator = new RNGCryptoServiceProvider();
private static readonly char[] ValidCharacters = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789".ToCharArray();
public const int DefaultLength = 6;
private static int counter = 0;
public static string Generate(int length = DefaultLength)
{
var randomData = new byte[length];
RandomGenerator.GetNonZeroBytes(randomData);
var result = new StringBuilder(DefaultLength);
foreach (var value in randomData)
{
counter = (counter + value) % (ValidCharacters.Length - 1);
result.Append(ValidCharacters[counter]);
}
return result.ToString();
}
}
In this instance it excludes 1 (one), I (i), 0 (zero) and O (o) for the sake of unambiguous human-readable output.
To determine just how effectively 'unique' your particular combination of valid characters and ID length are, the math is simple enough but it's still nice to have a 'code proof' of sorts (Xunit):
[Fact]
public void Does_not_generate_collisions_within_reasonable_number_of_iterations()
{
var ids = new HashSet<string>();
var minimumAcceptibleIterations = 10000;
for (int i = 0; i < minimumAcceptibleIterations; i++)
{
var result = LUID.Generate();
Assert.True(!ids.Contains(result), $"Collision on run {i} with ID '{result}'");
ids.Add(result);
}
}
No, it won't. A GUID has 128 bit length, a long only 64 bit, you are missing 64 bit of information, allowing for two GUIDs to generate the same long representation. While the chance is pretty slim, it is there.
Per the Guid.NewGuid MSDN page,
The chance that the value of the new Guid will be all zeros or equal to any other Guid is very low.
So, your method may produce a unique ID, but it's not guaranteed.
Yes, this will be most likely unique but since the number of bits are less than GUID, the chance of duplicate is more than a GUID - although still negligible.
Anyway, GUID itself does not guarantee uniqueness.
var s = Guid.NewGuid().ToString();
var h1 = s.Substring(0, s.Length / 2).GetHashCode(); // first half of Guid
var h2 = s.Substring(s.Length / 2).GetHashCode(); // second half of Guid
var result = (uint) h1 | (ulong) h2 << 32; // unique 8-byte long
var bytes = BitConverter.GetBytes(result);
P. S. It's very good, guys, that you are chatting with topic starter here. But what about answers that need other users, like me???
Like a few others have said, only taking part of the guid is a good way to ruin its uniqueness. Try something like this:
var bytes = new byte[8];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(bytes);
}
Console.WriteLine(BitConverter.ToInt64(bytes, 0));
enerates an 8-byte Ascii85 identifier based on the current timestamp in seconds.
Guaranteed unique for each second. 85% chance of no collisions for 5 generated Ids within the same second.
private static readonly Random Random = new Random();
public static string GenerateIdentifier()
{
var seconds = (int) DateTime.Now.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
var timeBytes = BitConverter.GetBytes(seconds);
var randomBytes = new byte[2];
Random.NextBytes(randomBytes);
var bytes = new byte[timeBytes.Length + randomBytes.Length];
System.Buffer.BlockCopy(timeBytes, 0, bytes, 0, timeBytes.Length);
System.Buffer.BlockCopy(randomBytes, 0, bytes, timeBytes.Length, randomBytes.Length);
return Ascii85.Encode(bytes);
}
As already said in most of the other answers: No, you can not just take a part of a GUID without losing the uniqueness.
If you need something that's shorter and still unique, read this blog post by Jeff Atwood:
Equipping our ASCII Armor
He shows multiple ways how to shorten a GUID without losing information. The shortest is 20 bytes (with ASCII85 encoding).
Yes, this is much longer than the 8 bytes you wanted, but it's a "real" unique GUID...while all attempts to cram something into 8 bytes most likely won't be truly unique.
In most cases bitwise XOR of both halves together is enough
Everyone in here is making this way more complicated than it needs to be. This is a terrible idea.
GUID 1: AAAA-BBBB-CCCC-DDDD
GUID 2: AAAA-BBBB-EEEE-FFFF
throw away the second half of each GUID, and now you have a duplicate identifier. GUIDs are not guaranteed to be unique, and its extremely awful. you shouldn't rely on the gurantee of whats generated, and it's not hard to get around this. If you need unique identifiers for an object, entity, or whatever, lets take a database for example - which is the most common, you should generate an id, see if it already exists, and insert it only if it doesn't. this is fast in databases since most tables are indexed based on ID. "most." if you have some kind of small object list in memory, or wherever, you'd probably store the entity in a hash table of some kind, in which you could just look it up to see if that generated GUID already exists.
all in all, depends on what your use case is really. a database, find the GUID first, and regenerate if possible until you can insert the new item. this really only matters in relational databases who dont automatically generate IDs for items in the tables. NoSQL DB's usually generate a unique identifier.
I have an object with the following properties
GID
ID
Code
Name
Some of the clients dont want to enter the Code so the intial plan was to put the ID in the code but the baseobject of the orm is different so I'm like screwed...
my plan was to put ####-#### totally random values in code how can I generate something like that say a windows 7 serial generator type stuff but would that not have an overhead what would you do in this case.
Do you want a random value, or a unique value?
random != unique.
Remember, random merely states a probability of not generating the same value, or a probability of generating the same value again. As time increases, likelihood of generating a previous value increases - becoming a near certainty. Which do you require?
Personally, I recommend just using a Guid with some context [refer to easiest section below]. I also provided some other suggestions so you have options, depending on your situation.
easiest
If Code is an unbounded string [ie can be of any length], easiest semi-legible means of generating a unique code would be
OrmObject ormObject= new OrmObject ();
string code = string.
Format ("{0} [{1}]", ormObject.Name, Guid.NewGuid ()).
Trim ();
// generates something like
// "My Product [DA9190E1-7FC6-49d6-9EA5-589BBE6E005E]"
you can substitute ormObject.Name for any distinguishable string. I would typically use typeof (objectInstance.GetType ()).Name but that will only work if OrmObject is a base class, if it's a concrete class used for everything they will all end up with similar tags. The point is to add some user context, such that - as in #Yuriy Faktorovich's referenced wtf article - users have something to read.
random
I responded a day or two ago about random number generation. Not so much generating numbers as building a simple flexible framework around a generator to improve quality of code and data, this should help streamline your source.
If you read that, you could easily write an extension method, say
public static class IRandomExtensions
{
public static CodeType GetCode (this IRandom random)
{
// 1. get as many random bytes as required
// 2. transform bytes into a 'Code'
// 3. bob's your uncle
...
}
}
// elsewhere in code
...
OrmObject ormObject = new OrmObject ();
ormObject.Code = random.GetCode ();
...
To actually generate a value, I would suggest implementing an IRandom interface with a System.Security.Cryptography.RNGCryptoServiceProvider implementation. Said implementation would generate a buffer of X random bytes, and dole out as many as required, regenerating a stream when exhausted.
Furthermore - I don't know why I keep writing, I guess this problem is really quite fascinating! - if CodeType is string and you want something readable, you could just take said random bytes and turn them into a "seemingly" readable string via Base64 conversion
public static class IRandomExtensions
{
// assuming 'CodeType' is in fact a string
public static string GetCode (this IRandom random)
{
// 1. get as many random bytes as required
byte[] randomBytes; // fill from random
// 2. transform bytes into a 'Code'
string randomBase64String =
System.Convert.ToBase64String (randomBytes).Trim ("=");
// 3. bob's your uncle
...
}
}
Remember
random != unique.
Your values will repeat. Eventually.
unique
There are a number of questions you need to ask yourself about your problem.
Must all Code values be unique? [if not, you're trying too hard]
What Type is Code? [if any-length string, use a full Guid]
Is this a distributed application? [if not, use a DB value as suggested by #LBushkin above]
If it is a distributed application, can client applications generate and submit instances of these objects? [if so, then you want a globally unique identifier, and again Guids are a sure bet]
I'm sure you have more constraints, but this is an example of the kind of line of inquiry you need to perform when you encounter a problem like your own. From these questions, you will come up with a series of constraints. These constraints will inform your design.
Hope this helps :)
Btw, you will receive better quality solutions if you post more details [ie constraints] about your problem. Again, what Type is Code, are there length constraints? Format constraints? Character constraints?
Arg, last edit, I swear. If you do end up using Guids, you may wish to obfuscate this, or even "compress" their representation by encoding them in base64 - similar to base64 conversion above for random numbers.
public static class GuidExtensions
{
public static string ToBase64String (this Guid id)
{
return System.Convert.
ToBase64String (id.ToByteArray ()).
Trim ("=");
}
}
Unlike truncating, base64 conversion is not a lossful transformation. Of course, the trim above is lossful in context of full base64 expansion - but = is just padding, extra information introduced by the conversion, and not part of original Guid data. If you want to go back to a Guid from this base64 converted value, then you will have to re-pad your base64 string until its length is a multiple of 4 - don't ask, just look up base64 if you are interested :)
You could generate a Guid using :
Guid.NewGuid().ToString();
It would give you something like :
788E94A0-C492-11DE-BFD4-FCE355D89593
Use an Autonumber column or Sequencer from your database to generate a unique code number. Almost all modern databases support automatically generated numbers in one form or another. Look into what you database supports.
Autonumber/Sequencer values from the DB are guaranteed to be unique and are relatively inexpensive to acquire. If you want to avoid completely sequential numbers assigned to codes, you can pad and concatenate several sequencer values together.