# Custom Data

{% hint style="info" %}
This article is not relevant if your custom data is already in a definition field. Instead, you can simply add the property to your [custom index definition](https://dev.ucommerce.net/readme/search-and-indexing/indexing/index-definitions).
{% endhint %}

If you wish to add custom or external data to your index, Ucommerce provides the interface `IAdorn<T>` where `T` is the search model type, e.g. `ProductSearchModel`. The interface provides 2 methods, one for general properties and one for language-specific (multilingual) properties:

{% code title="General properties" %}

```csharp
Task<IImmutableList<T>> Adorn(
            IImmutableList<T> items,
            DeserializedDataBase<T> rawData,
            CancellationToken token);
```

{% endcode %}

{% code title="Language-specific properties" %}

```csharp
Task<ImmutableDictionary<CultureInfo, IImmutableList<T>>> Adorn(
            ImmutableDictionary<CultureInfo, IImmutableList<T>> items,
            DeserializedDataBase<T> rawData,
            CancellationToken token);
```

{% endcode %}

{% hint style="danger" %}
You cannot store nested data structures; for instance, you cannot store a list of product relationships, each with its list of products. If you require such flexibility, you will need to create your own search model.
{% endhint %}

{% hint style="info" %}
In many cases it's only necessary to implement one of the two methods of the interface to add the desired data. When this happens, simply return the `items` parameter using `return await items.InTask();`in the other method.
{% endhint %}

Below is an example of an adorner that adds the product id to the product index.

{% hint style="warning" %}
It is not recommended to use the id externally. This is also the reason the id is not part of the search model.
{% endhint %}

{% hint style="warning" %}
The below adorner is not meant for production as it is not very performant to make a database call for each product to get the id.
{% endhint %}

```csharp
public class ProductIdAdorner : IAdorn<ProductSearchModel>
    {
        private readonly UcommerceDbContext _dbContext;

        /// <summary>
        /// Constructor
        /// </summary>
        public ProductIdAdorner(UcommerceDbContext dbContext)
        {
            _dbContext = dbContext;
        }
        
        /// <inheritdoc />
        public virtual async Task<IImmutableList<ProductSearchModel>> Adorn(
            IImmutableList<ProductSearchModel> items,
            DeserializedDataBase<ProductSearchModel> rawData,
            CancellationToken token)
        {
            foreach (var productSearchModel in items)
            {
                var productEntity = await _dbContext.Products.FirstAsync(p => p.Guid == productSearchModel.Id, token);
                productSearchModel["LegacyId"] = productEntity.Id;
            }

            return items;
        }

        /// <inheritdoc />
        public virtual Task<ImmutableDictionary<CultureInfo, IImmutableList<ProductSearchModel>>> Adorn(
            ImmutableDictionary<CultureInfo, IImmutableList<ProductSearchModel>> items,
            DeserializedDataBase<ProductSearchModel> rawData,
            CancellationToken token) =>
            items.InTask();
    }
```

To register your adorner, add it to the service collection like this:

```csharp
builder.Services.AddScoped<IAdorn<ProductSearchModel>, ProductIdAdorner>();
```

{% hint style="info" %}
Use `AddScoped` instead of `AddSingleton` if the adorner depends on any scoped instances, e.g. `UcommerceDbContext` like above. Microsoft Dependency Injection framework will let you know if you forget by throwing an exception on startup.
{% endhint %}

Remember to check that the property is part of the index definition, otherwise add it:

```csharp
this.Field(p => p["LegacyId"], typeof(int));
```

{% hint style="warning" %}
A rebuild of the indices is needed after changing the index definition.
{% endhint %}
