-1

I am using below code to generate unique id value from C# to save in db primary column. DBs like SQL, Mongodb, AWS redhsift (on these dbs i have unique id column) Can I go forward or is there complication in future ?

var milliSeconds = DateTimeOffset.UtcNow.UtcTicks.ToString();

long id = long.Parse(milliSeconds)

Thanks

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
Satya M
  • 29
  • 8
  • 3
    You should *not* assume that 2 people won't do the same thing at the *same* exact time. So no, using the time (accurate to 1/1000 of a second) is not an appropriate unique identifier. If racing drivers can manage to do a lap around 2-3 mile race track with the *exact* same time to 1/1000 (and sometimes 1/10000) of a second, and there's normally only 10's of them in a single session, then having 2 people out of 100's (1,000's? Millions?) doing the *same thing* at the *same time* has a very high likelihood in my opinion. – Thom A Sep 06 '22 at 14:01
  • @Larnu Can you please suggest if any other way to generate unique id for concurrent requests ? – Satya M Sep 06 '22 at 14:05
  • You may be better off letting the database manage your unique PK's when supported, RedShift, SQL etc. For those databases that do not support generating the keys then you may have better luck using Guid.NewGuid(). --> https://stackoverflow.com/questions/2977593/is-it-safe-to-assume-a-guid-will-always-be-unique – Ross Bush Sep 06 '22 at 14:06
  • SQL Server has the `IDENTITY` property. You also have `SEQUENCE` objects, and the `NEWID` and `NEWSEQUENTIALID` functions are guaranteed to not provide the same value twice for the same server. Each Database product has its own tools to handle generating such values. – Thom A Sep 06 '22 at 14:07
  • @RossBush i don't have any choice to use other datatype in db columns (only option bigint) – Satya M Sep 06 '22 at 14:09
  • agreed but only problem is with other then sql dbs, i have only way to generate from C# code with bigint or int numbers – Satya M Sep 06 '22 at 14:14
  • `IDENTITY` can be a `bigint`, as can `SEQUENCE` – Charlieface Sep 06 '22 at 14:29

2 Answers2

0

You can create a singleton class for it which contains a private counter and a method to retrieve the counter. However, the retrieve method has a lock so it get executed one thread at a time. Since it's a singleton class, it will instantiate once when the program gets run and you can initialize your counter from the maximum value available for id in your database and after that it would get increased without duplication or interruption.

Here's some sample code in console:

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 10; i++)
        {
            var counter = SingletonCounter.GetInstance();
            ThreadStart start = new ThreadStart(delegate
            {
                var id = counter.GetId();
            });
            new Thread(start).Start();
        }

        Console.ReadLine();
    }
}

public class SingletonCounter
{
    private static SingletonCounter _instance;
    private readonly object _object = new object();
    private long _id;
    private SingletonCounter()
    {
        _id = 0;//you can initiate with maximum id available in database when run the application
    }

    public static SingletonCounter GetInstance()
    {
        return _instance ??= new SingletonCounter();
    }

    public long GetId()
    {
        lock (_object)
        {
            Console.WriteLine(_id);
            return _id++;
        }
    }
}
  • And what do you do if running this application on two different machines accessing the same data store? – Charlieface Sep 06 '22 at 16:05
  • @Charlieface good point. Then maybe you should put this piece of code into a Independent service. A service with responsibility of creating id. – Pouya Hashemi Sep 06 '22 at 16:13
  • It's called a server with a database with an `IDENTITY` or `SEQUENCE`. I just don't see the need to reinvent the wheel. – Charlieface Sep 06 '22 at 19:26
  • @PouyaHashemi thanks , i want to add one more point what happened if we restart the services on server for latest updates – Satya M Sep 07 '22 at 05:19
  • @SatyaM when service is restarted it should retrive the maximum value of the id from database to initiate the _id field of the counter class. is that what you meant? – Pouya Hashemi Sep 07 '22 at 06:28
0

I am using another way to generate the unique bigint value it's works 99% but 1% is chance is that the project runs on multiple servers(load balancers)

public static int _staticNum = 1;
private static readonly object syncLock = new object();

 public static int GenerateStaticNum()
    {
        lock (syncLock)
        { // synchronize
            if (_staticNum == 99)
                _staticNum = 0;
            return _staticNum++;
        }
    }

    public long LatestScocuUniqueId()
    {
        string milliSeconds = DateTimeOffset.UtcNow.UtcTicks.ToString();
        int staticValue = GenerateStaticNum();
        string uid = milliSeconds.Substring(1);
        uid = uid + (staticValue < 10 ? "0" + staticValue.ToString() : staticValue.ToString());
        long id = long.Parse(uid);
        return id;
    }

Console.WriteLine(LatestScocuUniqueId());
Satya M
  • 29
  • 8