'How to guarantee a unique id without using GUID?

My multi-threaded program for invoice management's invoice class:

public class Invoice
    {
        [BsonId]
        public ObjectId Id { get; set; }
        public string from { get; set; }
        public string BillTo { get; set; }
        public int InvoiceNo { get; set; }
        public DateTime InvoiceDate { get; set; }
        public string GeneralDescription { get; set; }
        public float Tax { get; set; }
        public List<Item> Items { get; set; }
    }

The invoice no field should be incremented when a user creates a new invoice:

    {
        private static object _Synchronizer;
        public int MaxTillLoad;
        static BetterSerialGenerator()
        {
            _Synchronizer = new object();
        }
        public int Load()
        {
            lock (_Synchronizer)
            {
                GetMaxNumberClass MaxObtainer = new();
                MaxTillLoad = MaxObtainer.GetLargestInvoiceNo();
                return MaxTillLoad;
            }
        } 
        public int GenerateSerial(int MaxNoTillLoad)
        {
            lock (_Synchronizer)
            {
                return Interlocked.Increment(ref MaxNoTillLoad);
            }
        }
        public int GetSerial()
        {
            int maxtillload;
            maxtillload= this.Load();
            return this.GenerateSerial(maxtillload);
        }
    }

My function for inserting into MongoDB :

 public Task CreateInvoice(Invoice invoice)

        {
            _SerialGenerator.Load();
            invoice.InvoiceNo = _SerialGenerator.GetSerial();
            return InvoiceCollection.InsertOneAsync(invoice);  
        }

This generates the incremental id and inserts data into database. Now if I delete a record that has the maximum number, increment would cause duplication in invoice no. I need to guarantee that invoice no is unique even if an invoice is deleted.

I don't want to use a GUID. Should I save maximum Id and on deletion check if the Id is the maximum, if so make sure that maximum is in the file? What is the cleanest way to do so?

I decided to cache maximum like this :

    {
        private const string CacheKey = "maximuminvoiceno";
        private static object _Synchronizer;
        static Caching()
        {
            _Synchronizer = new object();
        }
        public int GetMaximumCachedInvoiceNo()
        {
            
            ObjectCache cache = System.Runtime.Caching.MemoryCache.Default;

            if (cache.Contains(CacheKey))
                return (int)cache.Get(CacheKey);
            else
            {
                int MaxInvoiceNo = this.GetMaxInvoiceNo();

                // Store data in the cache    
                CacheItemPolicy cacheItemPolicy = new CacheItemPolicy();
                cacheItemPolicy.AbsoluteExpiration = DateTime.Now.AddHours(1.0);
                cache.Add(CacheKey, MaxInvoiceNo, cacheItemPolicy);

                return MaxInvoiceNo;
            }
        }
        public int GetMaxInvoiceNo()

        {
            lock (_Synchronizer)
            {
                int MaxTillLoad;
                GetMaxNumberClass MaxObtainer = new();
                MaxTillLoad = MaxObtainer.GetLargestInvoiceNo();
                return MaxTillLoad;
            }
        }
    }
}

Now I am concerned that if application shuts down my data will be gone. Should I save it in database too?



Solution 1:[1]

Short answer is yes, you can store the maximum number in the DB. It's not a bad solution if you cache the number on application start up and handle updating it.

I am however concerned with your lock, you have a multi threading program and your lock is essentially stopping all threads and making them run synchronously.

I think a better solution would be to simply let the database handle all this logic by making the invoice Id unique.

If you want something a bit more complex than incrementing by a set value, you could also create a trigger at the database level.

Let me know if you need help with this :)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Geoffrey Fook