开发者

Generate 8 digit uinque id in c#

I need to generate 8 digit unique id in c#. On my site 开发者_JAVA技巧a user will register and I need to generate a unique id for him in c# code(I don't want this logic in DB), after inserting the id I need to save it in database.

Edit: I need that numbers to be generated in random manner everytime.


Although not 8 digits, I'd use a GUID for that purpose:

var id = Guid.NewGuid().ToString()

From Wikipedia:

Ideally, a GUID will never be generated twice by any computer or group of computers in existence. The total number of unique keys (2^128 or 3.4×10^38 - in relation there are about 1.33×10^50 atoms on earth) is so large that the probability of the same number being generated twice is extremely small, and certain techniques have been developed to help ensure that numbers are not duplicated


If you don't mind the IDs being predictable, I'd go with Vlad's suggestion.

Otherwise, I'd generate a random number in the required range and just try to insert it in the database... if you get an exception due to the uniqueness constraint being violated in the database (and that constraint absolutely should be there) then try again. Keep trying until it either works or you've gone round a certain number of times. (It's highly unlikely that you'll fail 100 times for example - unless you've got a bug elsewhere, in which case an exception is preferable to an infinite loop.)

So this isn't generating the ID in the database - but it's verifying the uniqueness in the database, which is after all the ultimate "source of truth".

If you don't need cryptographically securely generated IDs, then simply using Random.Next(100000000) will generate you a value in the range [0, 99999999]. If you don't want any values which need leading 0s to get to 8 digits, simply use Random.Next(10000000, 100000000) which will give you a smaller range of possible values, but you won't need to worry about them having fewer than 8 digits.

Using Random properly has a few "gotchas" - see my article about it for more details.


You could try to implement a method that generates a random number but you have always to check if it is already in database.

    static void Main(string[] args)
    {
        HashSet<string> numbers = new HashSet<string>();

        for (int i = 0; i < 100; i++)
        {
            numbers.Add(GenerateRandomNumber(8));
        }

        Console.WriteLine(numbers.Count == 100);
        Console.ReadLine();
    }

    static Random random = new Random();

    static string GenerateRandomNumber(int count)
    {
        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < count; i++)
        {
            int number = random.Next(10);
            builder.Append(number);
        }

        return builder.ToString();
    }


Why not just keep the last allocated number and increase it by 1 when allocating a new ID? Interlocked.Increment might be useful. You can pad the number with zeroes at the left to the 8 digits. Using int as backing type should be enough.

Edit: if you want the number to look random, just store in the DB not the allocated sequential numbers themselves, but use some bijective mapping. For example, you can store 7461873*ID + 17845612 instead. This guarantees the uniqueness and looks random.

By the way, this is similar how the random number generators usually work (only they don't use the sequential number, but rather the result of previous calculation).


Use Sequential Guids! Reduces the probability of a clash where guids already have a low probability of clashing and also means you can order your data by the Guid, representing the time of insertion.

    [DllImport("rpcrt4.dll", SetLastError = true)]
    static extern int UuidCreateSequential(out Guid guid);

    public static Guid SequentialGuid()
    {
        const int rpcSOk = 0;
        Guid guid;

        return UuidCreateSequential(out guid) != rpcSOk ? Guid.NewGuid() : guid;
    }

You can put this method in the base class for customers, or all entities and have it generated automagically in the base constructor on instatiation.


You can use Random Class

Random r=new Rand();
int id;
while((id=r.Next(10000000,99999999))!=someId); //check in database that Id is unique

Always remember that there is no technique to generate a unique Random number without checking existing values in database

You must have some information regarding previous values


You can also use my identify generator. But it's not integer one unfortunately. Make sure you have case sensitive ID column in db otherwise change the character range. The identifier is url friendly. Based on partial DateTime Ticks (10 characters) and partial Random (6 characters). It's not sortable so use AddedDate column instead to get a row sequence. Use varchar(16) column type and SQL_Latin1_General_CP1_CS_AS collation.

public static class IdentifyGenerator
{
    private static char[] sybmols = { 
                             '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                             'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
                         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
                         };

    public static string WebHash()
    {
        int length = sybmols.Length;
        ulong num = (ulong)DateTime.Now.Ticks;

        string output = string.Empty;
        ulong tmp = num;
        ulong mod = 0;
        while (tmp != 0)
        {
            mod = tmp % (ulong)length;
            tmp = tmp / (ulong)length;
            output = sybmols[mod] + output;
        }
        output += RandomString(6);
        return output;
    }

    public static string RandomString(int length)
    {
        Stack<byte> bytes = new Stack<byte>();
        string output = string.Empty;

        for (int i = 0; i < length; i++)
        {
            if (bytes.Count == 0)
            {
                bytes = new Stack<byte>(Guid.NewGuid().ToByteArray());
            }
            byte pop = bytes.Pop();
            output += sybmols[(int)pop % sybmols.Length];
        }
        return output;
    }
}

Unit Test:

[TestClass]
public class Code
{
    [TestMethod]
    public void IdentifyGeneratorTest()
    {
        var set = new HashSet<string>();
        for (int i = 1; i <= 1000000; i++)
        {
            var id = IdentifyGenerator.WebHash();
            if (!set.Add(id))
                Assert.Fail("IdentifyGenerator duplicate found");
        }
    }
}

Good luck.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜