Auto Incrementing IDs

NuGet Package Details

Package Name
Llamachant.ExpressApp.AutoIncrementingID

Overview

This module provides automated sequential incrementation of integer fields using database triggers, with built-in support for Microsoft SQL Server. It is designed with extensibility in mind, allowing you to add support for other database providers as needed.

Beyond simple incrementation, the module also supports grouped incrementation scenarios. For instance, you can configure it to reset and increment values from 1 based on a specific grouping key such as the start of each calendar year. These incremented values can then be referenced in calculated fields or used to enforce custom numbering schemes.

🌟 Key Features

Installation

Step 1: Install the Module

Install-Package 'Llamachant.ExpressApp.AutoIncrementingID'

Step 2: Register the Module

public override void Setup(XafApplication application) {
    base.Setup(application);
    this.RequiredModuleTypes.Add(typeof(LlamachantFrameworkAutoIncrementingIDModule));
}

OR

services.AddXaf(Configuration, builder => {
    builder.UseApplication<ExpressAppBlazorApplication>();
    builder.Modules.AddLlamachantFrameworkAutoIncrementingIDModule(); //Add this line
});

AutoIncrement Attribute

Add the AutoIncrement attribute to an integer property to let the module know you want a trigger created. You can add optional arguments to group by properties or expressions.

Simple Incrementing

using LlamachantFramework.AutoIncrementingID.Attributes;

private int _ID;
 [AutoIncrement]
 public int ID
 {
     get => _ID;
     set => SetPropertyValue<int>(nameof(ID), ref _ID, value);
 }
Results
Date Created ID
Jan 1 @ 9:00 am 1
Jan 1 @ 9:05 am 2
Jan 2 @ 8:00 am 3
Jan 2 @ 1:00 pm 4

Grouped Incrementing (By Day)

using LlamachantFramework.AutoIncrementingID.Attributes;

private int _ID;
 [AutoIncrement("GetDate([CreatedOn])")]
 public int ID
 {
     get => _ID;
     set => SetPropertyValue<int>(nameof(ID), ref _ID, value);
 }

private DateTime _CreatedOn;
public DateTime CreatedOn
{
    get { return _CreatedOn; }
    set { SetPropertyValue<DateTime>(nameof(CreatedOn), ref _CreatedOn, value); }
}

public override void AfterConstruction()
{
    base.AfterConstruction();
    _CreatedOn = DateTime.Now;
}
Results
Date Created ID
Jan 1 @ 9:00 am 1
Jan 1 @ 9:05 am 2
Jan 2 @ 8:00 am 1
Jan 2 @ 1:00 pm 2

IMPORTANT

Expressions such as LocalDateTimeToday() will not work as the trigger will convert this to the date and time of trigger creation.

TIP

You can group by multiple expressions for more complex scenarios.

Custom IDs

You can use persistent alias properties to handle custom ID fields. In the example below, we are creating a calculated field that concatenates several strings together to produce a Ticket #.

Example: Ticket #: 20300218-0001

Expression Value for Feb 18, 2030
'Ticket #:' Ticket #:
GETYEAR([CreatedOn]) 2030
PADLEFT(GETMONTH([CreatedOn]), 2, '0') 02
PADLEFT(GETDAY([CreatedOn]), 2, '0') 18
'-' -
[ID] 0001
using LlamachantFramework.AutoIncrementingID.Attributes;

[PersistentAlias(@"CONCAT(\
    'TICKET #: ',\
    GETYEAR([CreatedOn]),\
    PADLEFT(GETMONTH([CreatedOn]), 2, '0'),\
    PADLEFT(GETDAY([CreatedOn]), 2, '0'),\
    '-',\
    PADLEFT([ID], 4, '0'))")]
public string CustomID => Convert.ToString(EvaluateAlias(nameof(CustomID)));

private int _ID;
[Browsable(false)]
[AutoIncrement("GetDate([CreatedOn])")]
public int ID
{
    get => _ID;
    set => SetPropertyValue<int>(nameof(ID), ref _ID, value);
}

public override void AfterConstruction()
{
    base.AfterConstruction();
    _CreatedOn = DateTime.Now;
}
Results
Date Created ID CustomID
Jan 1, 2030 @ 9:00 am 1 Ticket # 20300101-0001
Jan 1, 2030 @ 9:05 am 2 Ticket # 20300101-0002
Jan 2, 2030 @ 8:00 am 1 Ticket # 20300102-0001
Jan 2, 2030 @ 1:00 pm 2 Ticket # 20300102-0002

Customizing Triggers

Triggers are created as part of the XAF ModuleUpdater process.

This module collects all properties that have an AutoIncrement attribute and generates an SQL statement for creating the trigger. You can override this SQL to generate your own trigger as needed.

TIP

If you want to support other database providers that use triggers, you'll need to provide the correct commands to create triggers for each property. This lets the module work with different types of databases and their specific syntax.

Subscribe to TriggerCreating

In your Module.cs file, handle the application's SetupComplete event to locate the LlamachantFrameworkAutoIncrementingIDModule. Once located, subscribe to its TriggerCreating event to customize or extend the behavior of the auto-increment trigger generation.

using LlamachantFramework.AutoIncrementingID;

public sealed class MyModule : ModuleBase {
    public override void Setup(XafApplication application)
    {
        base.Setup(application);
        application.SetupComplete += Application_SetupComplete;
    }

private void Application_SetupComplete(object sender, EventArgs e)
    {
        LlamachantFrameworkAutoIncrementingIDModule.FindModule(Application.Modules).TriggerCreating += ExpressAppWinModule_TriggerCreating;
    }

private void ExpressAppWinModule_TriggerCreating(object sender, AutoIncrementingID.Updaters.TriggerEventArgs e)
    {
        if (e.ObjectType.Type == typeof(Client) && e.Member.Name == nameof(Client.ID))
        {
            e.TriggerCreationQuery = "...custom trigger creation sql...";
            e.TriggerExistenceQuery = "...custom trigger existence query..."; //You can set this to null if needed
        }
    }
}