Skip to main content
.NET Standard 2.0+

Auto-Generate Unique Number Sequence

  • 4 minutes to read

Orders, Invoices, Articles, or other business entities often require an auto-filled Number or Code field that users can memorize. These user-friendly field values are sequential, but some gaps are allowed (for example, when a user deletes an order). Use one of the following techniques to use this field in XAF applications:

Database-Level Solution
This solution avoids sequence gaps. Since this solution is implemented at the database level, it is specific to the database type.
Explicit Transaction Solution
This solution is more complicated and implemented at the ORM level. It does not depend on the database type and also avoids sequence gaps.
DistributedIdGeneratorHelper Solution
An ORM-level solution. Sequence gaps may occur.

Database-Level Solution

Use the FetchOnly attribute as follows:

  1. Create an auto-increment database column (for example, Identity in SQL Server).
  2. Create a persistent property mapped to this column and decorate it with the FetchOnly attribute.

Explicit Transaction Solution

The following example shows how to implement the Explicit Transaction solution:

View Example: How to generate a sequential number for a persistent object within a database transaction

You can also review a sequence generator’s implementation in Expand Framework: SequenceGenerator.cs.

DistributedIdGeneratorHelper Solution

The following example uses built-in XAF classes to create unique auto-increment numbers:

View Example: How to generate a sequential and user-friendly identifier field within an XPO business class

In this technique, sequence gaps may occur.

Refresh the Identifier Field Value in the UI

If you use the Explicit Transaction or DistributedIdGeneratorHelper solution with UI-Level security, an application displays the identifier field value immediately after a user creates a new object. In the Integrated Mode and Middle-Tier Application Server configuration, the newly generated sequence number is displayed only after a manual refresh. XAF does not pass the sequence to the client immediately. Implement one of the techniques described below to refresh the field value automatically.

Override the Business Class OnSaved Method

Override your business class OnSaved method to update the value on the client side:

namespace MySolution.Module.BusinessObjects {  
    public class YourBusinessClass : YourBaseXpoClass {  
        // ...  
        protected override void OnSaved() {  
            base.OnSaved();  
            if(Number == 0) { //  0 is the default value of the sequence number property.
                Session.Reload(this);  
            }  
        }  
        // ...  
    }  
}  

Use a Custom Controller to Reload the Object Space

Use a custom Controller to reload the Object Space after new objects are saved:

namespace MySolution.Module.Controllers {  
    // ...  
    public class RefreshAfterCommitController : ViewController {  
        bool needRefresh = false;  
        public RefreshAfterCommitController() {  
            TargetViewNesting = Nesting.Root;  
        }  
        protected override void OnActivated() {  
            base.OnActivated();  
            ObjectSpace.Committed += ObjectSpace_Committed;  
            ObjectSpace.Committing += ObjectSpace_Committing;  
            ObjectSpace.Reloaded += ObjectSpace_Reloaded;  
        }  
        protected override void OnDeactivated() {  
            ObjectSpace.Committed -= ObjectSpace_Committed;  
            ObjectSpace.Committing -= ObjectSpace_Committing;  
            ObjectSpace.Reloaded -= ObjectSpace_Reloaded;  
            base.OnDeactivated();  
        }  
        private void ObjectSpace_Reloaded(object sender, EventArgs e) {  
            needRefresh = false;  
        }  
        private void ObjectSpace_Committing(object sender, System.ComponentModel.CancelEventArgs e) {  
            var objectSpace = (IObjectSpace)sender;  
            foreach (var obj in objectSpace.GetObjectsToSave(false)) {  
                if (objectSpace.IsNewObject(obj)) {  
                    needRefresh = true; break;  
                }  
            }  
        }  
        private void ObjectSpace_Committed(object sender, EventArgs e) {  
            if (needRefresh) {  
                ((IObjectSpace)sender).Refresh();  
                needRefresh = false;  
            }  
        }  
    }  
}  
See Also