# Auto Incrementing IDs

## NuGet Package Details

**Package Name**  
[Llamachant.ExpressApp.AutoIncrementingID](https://www.nuget.org/packages/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

- [AutoIncrement Attribute](/content/docs/Llamachant.ExpressApp.AutoIncrementingID#anchor-autoincrementattribute/index.html)
- [Custom IDs](/content/docs/Llamachant.ExpressApp.AutoIncrementingID#anchor-customids/index.html)
- [Customizing Triggers](/content/docs/Llamachant.ExpressApp.AutoIncrementingID#anchor-customizingtriggers/index.html)

## 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](https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.Updating.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
        }
    }
}
```
